Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: initial commit keygen app #1

Merged
merged 10 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions .cspell.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
{
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
"version": "0.2",
"ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log"],
"ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log", "/lib"],
"useGitignore": true,
"language": "en",
"words": ["dataurl", "devpool", "outdir", "servedir"],
"dictionaries": ["typescript", "node", "software-terms"],
"words": [
"libsodium",
"keypair",
"URLSAFE",
"scalarmult",
"URLSAFE",
"binkey",
"URLSAFE",
"binsec",
"binsec",
"binkey",
"URLSAFE",
"URLSAFE",
"scalarmult",
"dataurl",
"outdir",
"servedir",
],
"dictionaries": ["typescript", "node", "software-terms", "html"],
"import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"],
"ignoreRegExpList": ["[0-9a-fA-F]{6}"]
}
2 changes: 1 addition & 1 deletion .github/workflows/conventional-commits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ jobs:
name: Conventional Commits
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ubiquity/action-conventional-commits@master
28 changes: 22 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
# `@ubiquity/ts-template`
# `@ubiquity/keygen.ubq.fi`

This template repository includes support for the following:
### Generate a New Encrypted EVM Private Key

- TypeScript
- Environment Variables
- Conventional Commits
- Automatic deployment to Cloudflare Pages
1. **Visit the Key Generation Tool**
- Navigate to the permit key generation tool on the web.

2. **Generate a Key**
- Click on the "Generate" button on the webpage to initiate the key generation process.

3. **Input Your EVM Private Key**
- In the provided plain text field, paste your EVM Private Key. Ensure that it is 32 bytes in length.

4. **Encrypt Your Private Key**
- Once you've pasted your private key, click on the "Encrypt" button. This action will encrypt your private key, enhancing its security.

5. **Update GitHub Secrets**
- Copy the newly generated private key and update it on your GitHub Actions secret. Find the field labeled `x25519_PRIVATE_KEY` and replace its content with your generated x25519 private key.

6. **Update Configuration File**
- Next, take the cipher text, which is the encrypted version of your private key, and paste it into your `ubiquibot-config.yaml` file. Look for the field labeled `evmEncryptedPrivate` and replace its content with the cipher text.

7. **Double Check**
- Ensure that you've updated the GitHub Actions secret field `x25519_PRIVATE_KEY` with your already generated x25519 private key. This double check ensures that all components are aligned and your system remains secure.
12 changes: 5 additions & 7 deletions build/esbuild-build.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// @ts-expect-error - Could not find a declaration file for module
import esbuild from "esbuild";
const typescriptEntries = ["static/main.ts"];
// const cssEntries = ["static/style.css"];
const entries = [
...typescriptEntries,
// ...cssEntries
];
const typescriptEntries = ["static/scripts/key-generator/keygen.ts"];
const cssEntries = ["static/styles/rewards/rewards.css", "static/styles/audit-report/audit.css", "static/styles/onboarding/onboarding.css"];
export const entries = [...typescriptEntries, ...cssEntries];

export const esBuildContext: esbuild.BuildOptions = {
sourcemap: true,
Expand All @@ -19,7 +17,7 @@ export const esBuildContext: esbuild.BuildOptions = {
".ttf": "dataurl",
".svg": "dataurl",
},
outdir: "static/dist",
outdir: "static/out",
};

esbuild
Expand Down
4 changes: 2 additions & 2 deletions knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const config: KnipConfig = {
project: ["src/**/*.ts"],
ignore: ["src/types/config.ts"],
ignoreExportsUsedInFile: true,
ignoreDependencies: [],
ignoreDependencies: ["libsodium-wrappers", "eslint-config-prettier", "eslint-plugin-prettier"],
};

export default config;
export default config;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ts-template",
"version": "1.0.0",
"description": "Template repository with TypeScript support.",
"description": "X25519 Cipher generator for Ubiquity",
"main": "build/index.ts",
"author": "Ubiquity DAO",
"license": "MIT",
Expand All @@ -27,7 +27,8 @@
"open-source"
],
"dependencies": {
"dotenv": "^16.4.4"
"dotenv": "^16.4.4",
"libsodium-wrappers": "^0.7.13"
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",
Expand Down
41 changes: 34 additions & 7 deletions static/index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
<!doctype html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ubiquity TypeScript Template</title>
<link rel="stylesheet" href="style.css" />
<title>Key Generator</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="out/styles/onboarding/onboarding.css" rel="stylesheet" />
</head>
<body>
<h1>Ubiquity TypeScript Template</h1>
<script type="module" src="dist/main.js"></script>
<div class="container" id="keyGenContent">
<h1 class="title">Key Generator</h1>
<div class="mb-3">
<label for="privKey" class="form-label">x25519_PRIVATE_KEY</label>
<input type="text" class="form-control" id="privKey" />
</div>
<div class="mb-3">
<label for="pubKey" class="form-label">x25519_PUBLIC_KEY (Optional if private key is supplied)</label>
<input type="text" class="form-control" id="pubKey" />
</div>
<div class="mb-3">
<label for="plainKey" class="form-label">PLAIN_TEXT</label>
<input type="text" class="form-control" id="plainKey" />
</div>
<div class="mb-3">
<label for="cipherKey" class="form-label">CIPHER_TEXT</label>
<input type="text" class="form-control" id="cipherKey" />
</div>
<div class="mb-3">
<label for="statusKey" class="form-label">STATUS</label>
<input type="text" class="form-control" id="statusKey" disabled="true" />
</div>
<div class="btn-container">
<button type="button" class="btn btn-primary mb-3" id="genBtn">🔑 Generate</button>
<button type="button" class="btn btn-primary mb-3" id="encryptBtn">🔒 Encrypt</button>
<button type="button" class="btn btn-primary mb-3" id="decryptBtn">🔓 Decrypt</button>
</div>
</div>
<script src="out/scripts/key-generator/keygen.js" type="application/javascript"></script>
</body>
</html>
134 changes: 134 additions & 0 deletions static/scripts/key-generator/keygen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import _sodium from "libsodium-wrappers";

const classes = ["error", "warning", "success"];
const CYPHER_KEY = "#cipherKey";

function statusToggle(target: "error" | "warning" | "success", value: string) {
const statusKey = document.querySelector("#statusKey") as HTMLInputElement;

classes.forEach((e) => {
if (e !== target) {
statusKey.classList.remove(e);
}
});
statusKey.classList.add(target);
statusKey.value = value;
}

async function sodiumKeyBox() {
const privKey = document.querySelector("#privKey") as HTMLInputElement;
const pubKey = document.querySelector("#pubKey") as HTMLInputElement;
const cipherKey = document.querySelector(CYPHER_KEY) as HTMLInputElement;
cipherKey.value = "";
try {
await _sodium.ready;
const sodium = _sodium;

const { privateKey, publicKey } = sodium.crypto_box_keypair("base64");
privKey.value = privateKey;
pubKey.value = publicKey;
statusToggle("success", `Success: Key Generation is ok.`);
} catch (error: unknown) {
if (error instanceof Error) {
statusToggle("error", `Error: ${error.message}`);
} else {
statusToggle("error", `Error: ${JSON.stringify(error)}`);
}
}
}

async function sodiumEncryptedSeal() {
const pubKey = document.querySelector("#pubKey") as HTMLInputElement;
const privKey = document.querySelector("#privKey") as HTMLInputElement;
const plainKey = document.querySelector("#plainKey") as HTMLInputElement;
const cipherKey = document.querySelector(CYPHER_KEY) as HTMLInputElement;
try {
await _sodium.ready;
const sodium = _sodium;

if (!privKey.value && !pubKey.value) {
statusToggle("error", `Error: You need to enter either public or private key.`);
return;
}
if (!pubKey.value && privKey.value) {
// derive public key from private key
const binPriv = sodium.from_base64(privKey.value, sodium.base64_variants.URLSAFE_NO_PADDING);
const binPub = sodium.crypto_scalarmult_base(binPriv);
const output = sodium.to_base64(binPub, sodium.base64_variants.URLSAFE_NO_PADDING);
pubKey.value = output;
}
const binkey = sodium.from_base64(pubKey.value, sodium.base64_variants.URLSAFE_NO_PADDING);
const binsec = sodium.from_string(plainKey.value);
const encBytes = sodium.crypto_box_seal(binsec, binkey);
const output = sodium.to_base64(encBytes, sodium.base64_variants.URLSAFE_NO_PADDING);
cipherKey.value = output;
statusToggle("success", `Success: Key Encryption is ok.`);
} catch (error: unknown) {
if (error instanceof Error) {
statusToggle("error", `Error: ${error.message}`);
} else {
statusToggle("error", `Error: ${JSON.stringify(error)}`);
}
}
}

async function sodiumOpenSeal() {
const pubKey = document.querySelector("#pubKey") as HTMLInputElement;
const privKey = document.querySelector("#privKey") as HTMLInputElement;
const cipherKey = document.querySelector("#cipherKey") as HTMLInputElement;
const plainKey = document.querySelector("#plainKey") as HTMLInputElement;
try {
await _sodium.ready;
const sodium = _sodium;

if (!privKey.value) {
statusToggle("error", `Error: You need to enter private key.`);
return;
}
if (!pubKey.value && privKey.value) {
// derive public key from private key
const binPriv = sodium.from_base64(privKey.value, sodium.base64_variants.URLSAFE_NO_PADDING);
const binPub = sodium.crypto_scalarmult_base(binPriv);
const output = sodium.to_base64(binPub, sodium.base64_variants.URLSAFE_NO_PADDING);
pubKey.value = output;
}
const binPub = sodium.from_base64(pubKey.value, sodium.base64_variants.URLSAFE_NO_PADDING);
const binPriv = sodium.from_base64(privKey.value, sodium.base64_variants.URLSAFE_NO_PADDING);
const binCipher = sodium.from_base64(cipherKey.value, sodium.base64_variants.URLSAFE_NO_PADDING);
const outText = sodium.crypto_box_seal_open(binCipher, binPub, binPriv, "text");
plainKey.value = outText;
statusToggle("success", `Success: Key Decryption is ok.`);
} catch (error: unknown) {
if (error instanceof Error) {
statusToggle("error", `Error: ${error.message}`);
} else {
statusToggle("error", `Error: ${JSON.stringify(error)}`);
}
}
}

function init() {
const genBtn = document.querySelector("#genBtn") as HTMLButtonElement;
const encryptBtn = document.querySelector("#encryptBtn") as HTMLButtonElement;
const decryptBtn = document.querySelector("#decryptBtn") as HTMLButtonElement;

genBtn.addEventListener("click", () => {
sodiumKeyBox().catch((error) => {
statusToggle("error", `Error: ${error.message}`);
});
});

encryptBtn.addEventListener("click", () => {
sodiumEncryptedSeal().catch((error) => {
statusToggle("error", `Error: ${error.message}`);
});
});

decryptBtn.addEventListener("click", () => {
sodiumOpenSeal().catch((error) => {
statusToggle("error", `Error: ${error.message}`);
});
});
}

init();
Loading
Loading