Skip to content

Commit c88afdd

Browse files
committed
feat: update crypto and add actions
1 parent 8db84cd commit c88afdd

File tree

14 files changed

+172
-191
lines changed

14 files changed

+172
-191
lines changed

.github/workflows/release.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Tagged release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
check:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
node-version: [20.x]
14+
steps:
15+
- uses: actions/checkout@v3
16+
- uses: pnpm/action-setup@v3
17+
with:
18+
version: 8
19+
- uses: actions/setup-node@v3
20+
with:
21+
cache: "pnpm"
22+
node-version: ${{ matrix.node-version }}
23+
- run: pnpm install
24+
- run: pnpm test:node
25+
- run: pnpm test:jsdom
26+
release:
27+
needs: check
28+
runs-on: "ubuntu-latest"
29+
steps:
30+
- uses: "marvinpinto/action-automatic-releases@latest"
31+
with:
32+
repo_token: "${{ secrets.GITHUB_TOKEN }}"
33+
prerelease: false
34+
publish:
35+
needs: release
36+
runs-on: ubuntu-latest
37+
steps:
38+
- uses: actions/checkout@v3
39+
- uses: pnpm/action-setup@v3
40+
with:
41+
version: 8
42+
- uses: actions/setup-node@v3
43+
with:
44+
cache: "pnpm"
45+
node-version: ${{ matrix.node-version }}
46+
registry-url: "https://registry.npmjs.org"
47+
- run: pnpm install
48+
- run: pnpm publish --access public
49+
env:
50+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/test.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
matrix:
16+
node-version: [18.x, 20.x]
17+
steps:
18+
- uses: actions/checkout@v3
19+
- uses: pnpm/action-setup@v3
20+
with:
21+
version: 8
22+
- uses: actions/setup-node@v3
23+
with:
24+
cache: "pnpm"
25+
node-version: ${{ matrix.node-version }}
26+
- run: pnpm install
27+
- run: pnpm run test:node
28+
- run: pnpm run test:jsdom

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"editor.codeActionsOnSave": {
33
"source.organizeImports": "explicit"
4-
}
4+
},
5+
"cSpell.words": [
6+
"marvinpinto",
7+
"typedarrays"
8+
]
59
}

index.html

Lines changed: 0 additions & 12 deletions
This file was deleted.

lib/api-key/api-key.service.test.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

lib/api-key/api-key.service.ts

Lines changed: 1 addition & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,3 @@
1-
import AES from "crypto-js/aes";
2-
import Base64 from "crypto-js/enc-base64";
3-
import Hex from "crypto-js/enc-hex";
4-
import Utf8 from "crypto-js/enc-utf8";
5-
import WordArray from "crypto-js/lib-typedarrays";
6-
import MD5 from "crypto-js/md5";
7-
import CFB from "crypto-js/mode-cfb";
8-
import Pkcs7 from "crypto-js/pad-pkcs7";
91
import { BaseService } from "../common";
102

11-
export class APIKeyService extends BaseService {
12-
public static async encrypt(secretKey: string, payload: string) {
13-
const iv = WordArray.random(16);
14-
const key = MD5(secretKey);
15-
const value = Utf8.parse(payload).clone().concat(MD5(payload));
16-
// const value = Utf8.parse(payload);
17-
18-
console.log(value.sigBytes);
19-
20-
const encrypted = AES.encrypt(value, key, { iv: iv, mode: CFB, padding: Pkcs7 });
21-
22-
console.log({
23-
a: MD5(payload),
24-
b: iv.clone().concat(encrypted.ciphertext),
25-
});
26-
27-
return iv.clone().concat(encrypted.ciphertext).toString(Hex);
28-
}
29-
30-
public static async decrypt(secretKey: string, ciphertext: string) {
31-
const key = MD5(secretKey);
32-
const cipherData = Hex.parse(ciphertext);
33-
const iv = WordArray.create(cipherData.words.slice(0, 4), 16);
34-
const data = WordArray.create(cipherData.words.slice(4), cipherData.sigBytes - 16);
35-
const decrypted = AES.decrypt(data.toString(Base64), key, { iv: iv, mode: CFB });
36-
37-
console.log({ decrypted });
38-
39-
return decrypted.toString(Utf8);
40-
}
41-
}
42-
43-
function CryptJsWordArrayToUint8Array(wordArray: WordArray) {
44-
const l = wordArray.sigBytes;
45-
const words = wordArray.words;
46-
const result = new Uint8Array(l);
47-
var i = 0 /*dst*/,
48-
j = 0; /*src*/
49-
while (true) {
50-
// here i is a multiple of 4
51-
if (i == l) break;
52-
var w = words[j++];
53-
result[i++] = (w & 0xff000000) >>> 24;
54-
if (i == l) break;
55-
result[i++] = (w & 0x00ff0000) >>> 16;
56-
if (i == l) break;
57-
result[i++] = (w & 0x0000ff00) >>> 8;
58-
if (i == l) break;
59-
result[i++] = w & 0x000000ff;
60-
}
61-
return result;
62-
}
63-
64-
function hexStringToUint8Array(hexString: string) {
65-
if (hexString.length % 2 !== 0) {
66-
throw "Invalid hexString";
67-
} /*from w w w. j av a 2s . c o m*/
68-
var arrayBuffer = new Uint8Array(hexString.length / 2);
69-
70-
for (var i = 0; i < hexString.length; i += 2) {
71-
var byteValue = parseInt(hexString.substr(i, 2), 16);
72-
if (isNaN(byteValue)) {
73-
throw "Invalid hexString";
74-
}
75-
arrayBuffer[i / 2] = byteValue;
76-
}
77-
78-
return arrayBuffer;
79-
}
80-
81-
function convertUint8ArrayToWordArray(u8Array: Uint8Array): WordArray {
82-
var words = [],
83-
i = 0,
84-
len = u8Array.length;
85-
while (i < len) {
86-
words.push((u8Array[i++] << 24) | (u8Array[i++] << 16) | (u8Array[i++] << 8) | u8Array[i++]);
87-
}
88-
return WordArray.create(words, u8Array.length);
89-
}
3+
export class APIKeyService extends BaseService {}

lib/api-key/crypto.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { test } from "vitest";
2+
import { decrypt, encrypt } from "./crypto";
3+
4+
test("encrypt and decrypt", async (t) => {
5+
const key = "500c33c5485e4d7eb5c89dd8f33084dc";
6+
const data = `{ "uid": "001", "host": "www.example.com", "expired": 1741918889 }`;
7+
const encrypted = await encrypt(key, data);
8+
const decrypted = await decrypt(key, encrypted);
9+
t.expect(decrypted).toEqual(data);
10+
});

lib/api-key/crypto.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import AES from "crypto-js/aes";
2+
import Base64 from "crypto-js/enc-base64";
3+
import Hex from "crypto-js/enc-hex";
4+
import Utf8 from "crypto-js/enc-utf8";
5+
import WordArray from "crypto-js/lib-typedarrays";
6+
import MD5 from "crypto-js/md5";
7+
import CFB from "crypto-js/mode-cfb";
8+
import Pkcs7 from "crypto-js/pad-pkcs7";
9+
10+
export async function encrypt(secretKey: string, payload: string) {
11+
const iv = WordArray.random(16);
12+
const key = MD5(secretKey);
13+
const value = Utf8.parse(payload).clone().concat(MD5(payload));
14+
const encrypted = AES.encrypt(value, key, { iv: iv, mode: CFB, padding: Pkcs7 });
15+
return iv.clone().concat(encrypted.ciphertext).toString(Hex);
16+
}
17+
18+
export async function decrypt(secretKey: string, encrypted: string) {
19+
const key = MD5(secretKey);
20+
const cipherData = Hex.parse(encrypted);
21+
const iv = WordArray.create(cipherData.words.slice(0, 4), 16);
22+
const data = WordArray.create(cipherData.words.slice(4), cipherData.sigBytes - 16);
23+
const decrypted = AES.decrypt(data.toString(Base64), key, { iv: iv, mode: CFB, padding: Pkcs7 });
24+
const dataPart = WordArray.create(decrypted.words.slice(0, -4), decrypted.sigBytes - 16);
25+
const hashPart = uint8ArrayToWordArray(wordArrayToUint8Array(decrypted).slice(decrypted.sigBytes - 16));
26+
const result = dataPart.toString(Utf8);
27+
28+
if (MD5(result).toString(Hex) !== hashPart.toString(Hex)) {
29+
throw new Error("checksum invalid");
30+
}
31+
return result;
32+
}
33+
34+
function wordArrayToUint8Array(wordArray: WordArray) {
35+
const l = wordArray.sigBytes;
36+
const words = wordArray.words;
37+
const result = new Uint8Array(l);
38+
var i = 0,
39+
j = 0;
40+
while (true) {
41+
// here i is a multiple of 4
42+
if (i == l) break;
43+
var w = words[j++];
44+
result[i++] = (w & 0xff000000) >>> 24;
45+
if (i == l) break;
46+
result[i++] = (w & 0x00ff0000) >>> 16;
47+
if (i == l) break;
48+
result[i++] = (w & 0x0000ff00) >>> 8;
49+
if (i == l) break;
50+
result[i++] = w & 0x000000ff;
51+
}
52+
return result;
53+
}
54+
55+
function uint8ArrayToWordArray(u8Array: Uint8Array) {
56+
var words = [],
57+
i = 0,
58+
len = u8Array.length;
59+
while (i < len) {
60+
words.push((u8Array[i++] << 24) | (u8Array[i++] << 16) | (u8Array[i++] << 8) | u8Array[i++]);
61+
}
62+
return WordArray.create(words, u8Array.length);
63+
}

lib/api-key/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./api-key";
22
export * from "./api-key.service";
33
export * from "./api-token-payload";
4+
export * from "./crypto";

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"module": "./dist/index.js",
77
"types": "./dist/index.d.ts",
88
"scripts": {
9-
"dev": "vite",
9+
"dev": "vite build --watch",
1010
"test:node": "vitest --watch=false --environment=node",
1111
"test:jsdom": "vitest --watch=false --environment=jsdom",
1212
"build": "vite build",
@@ -26,7 +26,7 @@
2626
"vite": "^5.1.6",
2727
"vite-plugin-checker": "^0.6.4",
2828
"vite-plugin-dts": "^3.7.3",
29-
"vite-tsconfig-paths": "^4.3.1",
29+
"vite-plugin-externalize-deps": "^0.8.0",
3030
"vitest": "^1.3.1"
3131
},
3232
"dependencies": {

0 commit comments

Comments
 (0)