-
Notifications
You must be signed in to change notification settings - Fork 4
/
Hash.ts
112 lines (94 loc) · 3.36 KB
/
Hash.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import {WebFileStream} from '@cubbit/web-file-stream';
import {Duplex} from 'stream';
import {defaults} from '../../defaults';
import {em_array_free, em_array_malloc} from '../utils';
export declare namespace Hash
{
export interface Options
{
algorithm?: Algorithm;
encoding?: Encoding;
}
}
export class HashStream extends Duplex
{
private _context: any;
public constructor()
{
super();
this._context = (self as any).enigma.SHA256.context();
this.on('finish', () =>
{
const hash = (self as any).enigma.SHA256.finalize(this._context.byteOffset);
this.push(Buffer.from(hash));
this._context = null;
});
}
public _write(chunk: Buffer, _: string, callback: any): void
{
try
{
const heap_chunk = em_array_malloc((self as any).enigma, chunk);
(self as any).enigma.SHA256.update(this._context.byteOffset, heap_chunk.byteOffset, chunk.length);
em_array_free((self as any).enigma, heap_chunk);
callback();
}
catch(error)
{
callback(error);
}
}
// tslint:disable-next-line:no-empty
public _read(_: number): void {}
}
export class Hash
{
public static async digest(message: string | Buffer, options?: Hash.Options): Promise<string>
{
// @ts-ignore
const algorithm: Hash.Algorithm = (options && options.algorithm) || Hash.Algorithm[defaults.hash.algorithm as any] as Hash.Algorithm;
// @ts-ignore
const encoding: Hash.Encoding = (options && options.encoding) || Hash.Encoding[defaults.hash.encoding as any] as Hash.Encoding;
if(typeof message === 'string')
message = Buffer.from(message, 'utf8');
return Buffer.from(await self.crypto.subtle.digest({name: algorithm}, message)).toString(encoding);
}
public static async digest_file(file: string | File, options?: Hash.Options): Promise<string>
{
return new Promise<string>((resolve, reject) =>
{
if(typeof file === 'string')
return reject('Path not supported. First argument must be a File');
// @ts-ignore
const algorithm: Hash.Algorithm = (options && options.algorithm) || Hash.Algorithm[defaults.hash.algorithm as any] as Hash.Algorithm;
// @ts-ignore
const encoding = (options && options.encoding) || Hash.Encoding[defaults.hash.encoding as any] as Hash.Encoding;
if(algorithm !== Hash.Algorithm.SHA256)
return reject(new Error('Unsupported algorithm'));
const stream = new HashStream();
stream.on('error', reject);
stream.on('finish', () => resolve(stream.read().toString(encoding)));
WebFileStream.create_read_stream(file).pipe(stream);
});
}
// @ts-ignore
public static stream(algorithm: Hash.Algorithm = Hash.Algorithm[defaults.hash.algorithm as any] as Hash.Algorithm): HashStream
{
if(algorithm !== Hash.Algorithm.SHA256)
throw new Error('Unsupported algorithm for stream');
return new HashStream();
}
}
// tslint:disable-next-line:no-namespace
export namespace Hash
{
export enum Algorithm
{
SHA256 = 'SHA-256'
}
export enum Encoding
{
BASE64 = 'base64',
HEX = 'hex'
}
}