16 lines
1.3 KiB
TypeScript
16 lines
1.3 KiB
TypeScript
export interface EncryptedLogin { key: CryptoKey; iv: Uint8Array; ciphertext: ArrayBuffer }
|
|
export interface LoginFields { username: string; password: string }
|
|
const encoder = new TextEncoder();
|
|
export async function encryptLogin(fields: LoginFields, endpoint: string): Promise<EncryptedLogin> {
|
|
const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']);
|
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, additionalData: encoder.encode(`webdrop-login:${endpoint}`) }, key, encoder.encode(JSON.stringify(fields)));
|
|
return { key, iv, ciphertext };
|
|
}
|
|
export async function decryptLogin(value: EncryptedLogin, endpoint: string): Promise<LoginFields> {
|
|
const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: Uint8Array.from(value.iv).buffer, additionalData: encoder.encode(`webdrop-login:${endpoint}`) }, value.key, value.ciphertext);
|
|
const fields = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(plaintext)) as LoginFields;
|
|
if (typeof fields.username !== 'string' || !/^[a-z0-9_-]{3,32}$/.test(fields.username) || typeof fields.password !== 'string' || fields.password.length > 1024) throw new Error('本机登录资料格式无效');
|
|
return fields;
|
|
}
|