mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-01 20:42:50 +08:00
feat: add TS3 identity generation with Ed25519 keypairs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bc89c553b7
commit
2b6e81119b
4 files changed
+73
No files matched your search
Generated
+7
@@ -12,6 +12,7 @@
|
|||||||
"better-sqlite3": "^12.8.0",
|
"better-sqlite3": "^12.8.0",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"pino": "^10.3.1",
|
"pino": "^10.3.1",
|
||||||
|
"tweetnacl": "^1.0.3",
|
||||||
"ws": "^8.20.0"
|
"ws": "^8.20.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -3080,6 +3081,12 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
"node_modules/type-is": {
|
"node_modules/type-is": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"better-sqlite3": "^12.8.0",
|
"better-sqlite3": "^12.8.0",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"pino": "^10.3.1",
|
"pino": "^10.3.1",
|
||||||
|
"tweetnacl": "^1.0.3",
|
||||||
"ws": "^8.20.0"
|
"ws": "^8.20.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { generateIdentity, exportIdentity, importIdentity } from "./identity.js";
|
||||||
|
|
||||||
|
describe("TS3 Identity", () => {
|
||||||
|
it("generates a valid identity with keypair", () => {
|
||||||
|
const identity = generateIdentity();
|
||||||
|
expect(identity.publicKey).toBeInstanceOf(Uint8Array);
|
||||||
|
expect(identity.privateKey).toBeInstanceOf(Uint8Array);
|
||||||
|
expect(identity.publicKey.length).toBe(32);
|
||||||
|
expect(identity.privateKey.length).toBe(64);
|
||||||
|
expect(identity.uid).toBeTruthy();
|
||||||
|
expect(typeof identity.uid).toBe("string");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exports and imports identity consistently", () => {
|
||||||
|
const identity = generateIdentity();
|
||||||
|
const exported = exportIdentity(identity);
|
||||||
|
const imported = importIdentity(exported);
|
||||||
|
expect(imported.uid).toBe(identity.uid);
|
||||||
|
expect(imported.publicKey).toEqual(identity.publicKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("generates unique identities each time", () => {
|
||||||
|
const id1 = generateIdentity();
|
||||||
|
const id2 = generateIdentity();
|
||||||
|
expect(id1.uid).not.toBe(id2.uid);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import nacl from "tweetnacl";
|
||||||
|
import crypto from "node:crypto";
|
||||||
|
|
||||||
|
export interface TS3Identity {
|
||||||
|
publicKey: Uint8Array;
|
||||||
|
privateKey: Uint8Array;
|
||||||
|
uid: string; // base64-encoded SHA1 of public key
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateIdentity(): TS3Identity {
|
||||||
|
const keypair = nacl.sign.keyPair();
|
||||||
|
const uid = computeUid(keypair.publicKey);
|
||||||
|
return {
|
||||||
|
publicKey: keypair.publicKey,
|
||||||
|
privateKey: keypair.secretKey,
|
||||||
|
uid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computeUid(publicKey: Uint8Array): string {
|
||||||
|
return crypto.createHash("sha1").update(publicKey).digest("base64");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exportIdentity(identity: TS3Identity): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
publicKey: Buffer.from(identity.publicKey).toString("base64"),
|
||||||
|
privateKey: Buffer.from(identity.privateKey).toString("base64"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function importIdentity(data: string): TS3Identity {
|
||||||
|
const parsed = JSON.parse(data) as { publicKey: string; privateKey: string };
|
||||||
|
const publicKey = new Uint8Array(Buffer.from(parsed.publicKey, "base64"));
|
||||||
|
const privateKey = new Uint8Array(Buffer.from(parsed.privateKey, "base64"));
|
||||||
|
const uid = computeUid(publicKey);
|
||||||
|
return { publicKey, privateKey, uid };
|
||||||
|
}
|
||||||
Reference in new issue
Block a user