UNPKG

2.31 kBJavaScriptView Raw
1import { createHmac } from 'crypto';
2export class SignaturError extends Error {
3 constructor(type, message) {
4 super();
5 this.name = 'SignaturError';
6 this.message = message;
7 this.type = type;
8 }
9 toJSON() {
10 return {
11 error: {
12 type: this.type,
13 message: this.message,
14 },
15 };
16 }
17}
18function urlSafeBase64(s) {
19 return s.replace(/\+/gi, '-').replace(/\//gi, '_').replace(/=/gi, '');
20}
21export function signSync(data, secret, options) {
22 const { separator = '.' } = options || {};
23 if (null == data) {
24 throw new TypeError(`Expected 'data' to be defined, but received '${JSON.stringify(data)}'`);
25 }
26 if ('string' !== typeof (secret) || !secret.length) {
27 throw new TypeError(`Expected 'secret' to be defined, but received '${secret}'`);
28 }
29 const stringData = JSON.stringify({ data });
30 const encoded = Buffer.from(stringData, 'utf8').toString('base64');
31 const signature = createHmac('sha256', secret).update(stringData).digest('base64');
32 return urlSafeBase64(`${encoded}${separator}${signature}`);
33}
34export function unsignSync(signature, secret, options) {
35 const { separator = '.' } = options || {};
36 if ('string' !== typeof (signature) || !signature.length) {
37 throw new TypeError(`Expected 'signature' to be defined, but received '${signature}'`);
38 }
39 if ('string' !== typeof (secret) || !secret.length) {
40 throw new TypeError(`Expected 'secret' to be defined, but received '${secret}'`);
41 }
42 const [hash, enc] = signature.split(separator, 2);
43 const decoded = Buffer.from((hash + '==='.slice((hash.length + 3) % 4))
44 .replace(/\-/gi, '+')
45 .replace(/_/gi, '/'), 'base64')
46 .toString('utf8');
47 const signedDecoded = urlSafeBase64(createHmac('sha256', secret).update(decoded).digest('base64'));
48 if (enc !== signedDecoded) {
49 throw new SignaturError('invalid_signature', 'Signature not match');
50 }
51 return JSON.parse(decoded).data;
52}
53export async function sign(data, secret, options) {
54 return signSync(data, secret, options);
55}
56export async function unsign(signature, secret, options) {
57 return unsignSync(signature, secret, options);
58}
59//# sourceMappingURL=index.js.map
\No newline at end of file