Files
bunq/ts/bunq.classes.crypto.ts
Juergen Kunz f530fa639a update
2025-07-18 11:33:13 +00:00

120 lines
2.7 KiB
TypeScript

import * as plugins from './bunq.plugins.js';
export class BunqCrypto {
private privateKey: string;
private publicKey: string;
constructor() {}
/**
* Generate a new RSA key pair for bunq API communication
*/
public async generateKeyPair(): Promise<void> {
const keyPair = plugins.crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
this.privateKey = keyPair.privateKey;
this.publicKey = keyPair.publicKey;
}
/**
* Get the public key
*/
public getPublicKey(): string {
if (!this.publicKey) {
throw new Error('Public key not generated yet');
}
return this.publicKey;
}
/**
* Get the private key
*/
public getPrivateKey(): string {
if (!this.privateKey) {
throw new Error('Private key not generated yet');
}
return this.privateKey;
}
/**
* Set keys from stored values
*/
public setKeys(privateKey: string, publicKey: string): void {
this.privateKey = privateKey;
this.publicKey = publicKey;
}
/**
* Sign data with the private key
*/
public signData(data: string): string {
if (!this.privateKey) {
throw new Error('Private key not set');
}
const sign = plugins.crypto.createSign('SHA256');
sign.update(data);
sign.end();
return sign.sign(this.privateKey, 'base64');
}
/**
* Verify data with the server's public key
*/
public verifyData(data: string, signature: string, serverPublicKey: string): boolean {
const verify = plugins.crypto.createVerify('SHA256');
verify.update(data);
verify.end();
return verify.verify(serverPublicKey, signature, 'base64');
}
/**
* Create request signature header (signs only body per bunq docs)
*/
public createSignatureHeader(
method: string,
endpoint: string,
headers: { [key: string]: string },
body: string = ''
): string {
// According to bunq docs, only sign the request body
return this.signData(body);
}
/**
* Verify response signature (signs only body per bunq API behavior)
*/
public verifyResponseSignature(
statusCode: number,
headers: { [key: string]: string },
body: string,
serverPublicKey: string
): boolean {
const responseSignature = headers['x-bunq-server-signature'];
if (!responseSignature) {
return false;
}
// According to bunq API behavior, only the response body is signed
return this.verifyData(body, responseSignature, serverPublicKey);
}
/**
* Generate a random request ID
*/
public generateRequestId(): string {
return plugins.crypto.randomUUID();
}
}