firefly-compiler 0.4.36 → 0.4.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.hintrc +4 -4
- package/.vscode/settings.json +4 -4
- package/bin/Release.ff +99 -49
- package/bin/firefly.mjs +1 -1
- package/compiler/Builder.ff +257 -257
- package/compiler/Compiler.ff +227 -227
- package/compiler/Dependencies.ff +186 -186
- package/compiler/DependencyLock.ff +17 -17
- package/compiler/JsEmitter.ff +946 -946
- package/compiler/LspHook.ff +202 -202
- package/compiler/ModuleCache.ff +178 -178
- package/compiler/Workspace.ff +88 -88
- package/core/.firefly/include/package-lock.json +394 -394
- package/core/.firefly/include/package.json +5 -5
- package/core/.firefly/include/prepare.sh +1 -1
- package/core/.firefly/package.ff +2 -2
- package/core/Array.ff +265 -265
- package/core/Atomic.ff +64 -64
- package/core/Box.ff +7 -7
- package/core/BrowserSystem.ff +40 -37
- package/core/Buffer.ff +3 -3
- package/core/BuildSystem.ff +148 -145
- package/core/Crypto.ff +96 -95
- package/core/Equal.ff +36 -36
- package/core/HttpClient.ff +87 -87
- package/core/Instant.ff +17 -0
- package/core/JsSystem.ff +69 -69
- package/core/Json.ff +434 -434
- package/core/List.ff +415 -415
- package/core/Lock.ff +144 -144
- package/core/NodeSystem.ff +189 -189
- package/core/Ordering.ff +161 -161
- package/core/Path.ff +401 -401
- package/core/Random.ff +134 -134
- package/core/RbMap.ff +216 -216
- package/core/Show.ff +43 -43
- package/core/SourceLocation.ff +68 -68
- package/core/Stream.ff +1 -1
- package/core/Task.ff +141 -141
- package/experimental/benchmarks/ListGrab.ff +23 -23
- package/experimental/benchmarks/ListGrab.java +55 -55
- package/experimental/benchmarks/Pyrotek45.ff +30 -30
- package/experimental/benchmarks/Pyrotek45.java +64 -64
- package/experimental/bidirectional/Bidi.ff +88 -88
- package/experimental/random/Index.ff +53 -53
- package/experimental/random/Process.ff +120 -120
- package/experimental/random/RunLength.ff +3 -3
- package/experimental/random/Scrape.ff +51 -51
- package/experimental/random/Symbols.ff +73 -73
- package/experimental/random/Tensor.ff +52 -52
- package/experimental/random/Units.ff +36 -36
- package/experimental/s3/S3TestAuthorizationHeader.ff +38 -38
- package/experimental/s3/S3TestPut.ff +15 -15
- package/experimental/tests/TestJson.ff +26 -26
- package/firefly.sh +0 -0
- package/fireflysite/Main.ff +13 -13
- package/lsp/.firefly/package.ff +1 -1
- package/lsp/CompletionHandler.ff +811 -811
- package/lsp/Handler.ff +714 -714
- package/lsp/HoverHandler.ff +79 -79
- package/lsp/LanguageServer.ff +272 -272
- package/lsp/SignatureHelpHandler.ff +55 -55
- package/lsp/SymbolHandler.ff +181 -181
- package/lsp/TestReferences.ff +16 -16
- package/lsp/TestReferencesCase.ff +7 -7
- package/lsp/stderr.txt +1 -1
- package/lsp/stdout.txt +34 -34
- package/lux/.firefly/package.ff +1 -1
- package/lux/Css.ff +648 -648
- package/lux/CssTest.ff +48 -48
- package/lux/Lux.ff +487 -487
- package/lux/LuxEvent.ff +116 -116
- package/lux/Main.ff +128 -128
- package/lux/Main2.ff +144 -144
- package/output/js/ff/compiler/Builder.mjs +43 -43
- package/output/js/ff/compiler/Dependencies.mjs +3 -3
- package/output/js/ff/core/Array.mjs +59 -59
- package/output/js/ff/core/Atomic.mjs +36 -36
- package/output/js/ff/core/BrowserSystem.mjs +19 -11
- package/output/js/ff/core/Buffer.mjs +7 -7
- package/output/js/ff/core/BuildSystem.mjs +38 -30
- package/output/js/ff/core/Crypto.mjs +67 -68
- package/output/js/ff/core/HttpClient.mjs +24 -24
- package/output/js/ff/core/Instant.mjs +38 -0
- package/output/js/ff/core/Json.mjs +147 -147
- package/output/js/ff/core/List.mjs +50 -50
- package/output/js/ff/core/Lock.mjs +97 -97
- package/output/js/ff/core/NodeSystem.mjs +77 -77
- package/output/js/ff/core/Ordering.mjs +8 -8
- package/output/js/ff/core/Path.mjs +231 -231
- package/output/js/ff/core/Random.mjs +56 -56
- package/output/js/ff/core/Stream.mjs +2 -2
- package/output/js/ff/core/Task.mjs +31 -31
- package/package.json +29 -29
- package/rpc/.firefly/package.ff +1 -1
- package/rpc/Rpc.ff +69 -69
- package/s3/.firefly/package.ff +1 -0
- package/{experimental/s3 → s3}/S3.ff +92 -92
- package/unsafejs/UnsafeJs.ff +19 -19
- package/vscode/LICENSE.txt +21 -21
- package/vscode/Prepublish.ff +15 -15
- package/vscode/README.md +16 -16
- package/vscode/client/package.json +22 -22
- package/vscode/client/src/extension.ts +104 -104
- package/vscode/icons/firefly-icon.svg +10 -10
- package/vscode/language-configuration.json +61 -61
- package/vscode/package-lock.json +3623 -3623
- package/vscode/package.json +160 -160
- package/vscode/snippets.json +241 -241
- package/webserver/.firefly/include/package-lock.json +16 -16
- package/webserver/.firefly/include/package.json +5 -5
- package/webserver/.firefly/package.ff +2 -2
- package/webserver/WebServer.ff +685 -685
- package/websocket/.firefly/package.ff +1 -1
- package/websocket/WebSocket.ff +131 -131
- package/crypto/SubtleCrypto.ff +0 -149
package/core/Box.ff
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
class Box[T](mutable value: T)
|
|
2
|
-
|
|
3
|
-
extend self[T]: Box[T] {
|
|
4
|
-
modify(body: T => T): Unit {
|
|
5
|
-
self.value = body(self.value)
|
|
6
|
-
}
|
|
7
|
-
}
|
|
1
|
+
class Box[T](mutable value: T)
|
|
2
|
+
|
|
3
|
+
extend self[T]: Box[T] {
|
|
4
|
+
modify(body: T => T): Unit {
|
|
5
|
+
self.value = body(self.value)
|
|
6
|
+
}
|
|
7
|
+
}
|
package/core/BrowserSystem.ff
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
|
-
capability BrowserSystem {}
|
|
2
|
-
|
|
3
|
-
extend self: BrowserSystem {
|
|
4
|
-
|
|
5
|
-
httpClient(): HttpClient
|
|
6
|
-
target js async "return null"
|
|
7
|
-
|
|
8
|
-
mainTask(): Task
|
|
9
|
-
target js async "return self_.task_"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
target js async "return typeof globalThis !== 'undefined' ? globalThis : window"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
target js async ""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
capability BrowserSystem {}
|
|
2
|
+
|
|
3
|
+
extend self: BrowserSystem {
|
|
4
|
+
|
|
5
|
+
httpClient(): HttpClient
|
|
6
|
+
target js async "return null"
|
|
7
|
+
|
|
8
|
+
mainTask(): Task
|
|
9
|
+
target js async "return self_.task_"
|
|
10
|
+
|
|
11
|
+
crypto(): Crypto
|
|
12
|
+
target js async "return (typeof globalThis !== 'undefined' ? globalThis : window).crypto"
|
|
13
|
+
|
|
14
|
+
js(): JsSystem
|
|
15
|
+
target js async "return typeof globalThis !== 'undefined' ? globalThis : window"
|
|
16
|
+
|
|
17
|
+
url(): String
|
|
18
|
+
target js async """
|
|
19
|
+
return location.href;
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
urlPath(): String
|
|
23
|
+
target js async """
|
|
24
|
+
return location.pathname;
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
urlQuery(name: String): Option[String]
|
|
28
|
+
target js async """
|
|
29
|
+
const param = new URLSearchParams(location.search).get(name_)
|
|
30
|
+
if(param == null) return ff_core_Option.None();
|
|
31
|
+
return ff_core_Option.Some(param);
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
urlFragment(): Option[String]
|
|
35
|
+
target js async """
|
|
36
|
+
if(!location.hash.startsWith('#')) return ff_core_Option.None();
|
|
37
|
+
return ff_core_Option.Some(location.hash.slice(1));
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
}
|
package/core/Buffer.ff
CHANGED
|
@@ -143,10 +143,10 @@ extend self: Buffer {
|
|
|
143
143
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
fromByteList(array: List[Int]): Buffer
|
|
147
147
|
target js sync "return new DataView(new Uint8Array(array_).buffer)"
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
fromBufferList(array: List[Buffer]): Buffer
|
|
150
150
|
target js sync """
|
|
151
151
|
let length = 0
|
|
152
152
|
for(let b of array_) length += b.byteLength
|
|
@@ -162,7 +162,7 @@ fromBufferArray(array: List[Buffer]): Buffer
|
|
|
162
162
|
|
|
163
163
|
fromHex(hex: String): Buffer
|
|
164
164
|
target js sync """
|
|
165
|
-
const hexValues =
|
|
165
|
+
const hexValues = hex_.match(/.{1,2}/g) || []
|
|
166
166
|
const numbers = hexValues.map(value => parseInt(value, 16))
|
|
167
167
|
return new DataView(new Uint8Array(numbers).buffer)
|
|
168
168
|
"""
|
package/core/BuildSystem.ff
CHANGED
|
@@ -1,145 +1,148 @@
|
|
|
1
|
-
capability BuildSystem {}
|
|
2
|
-
capability BrowserCode(packageGroup: String, packageName: String, mainFile: Path, assetSystem: AssetSystem)
|
|
3
|
-
capability BrowserBundle(assetSystem: AssetSystem)
|
|
4
|
-
|
|
5
|
-
extend self: BuildSystem {
|
|
6
|
-
|
|
7
|
-
compileForBrowser(mainFile: String): BrowserCode {
|
|
8
|
-
// TODO: Check that the mainFile is in the current package directory
|
|
9
|
-
internalCompile(self, internalPath(self, mainFile), "browser")
|
|
10
|
-
let streams = internalListDirectory(internalPath(self, ".firefly/output/browser"))
|
|
11
|
-
let mainPackagePair = internalMainPackagePair(self)
|
|
12
|
-
BrowserCode(
|
|
13
|
-
packageGroup = mainPackagePair.first
|
|
14
|
-
packageName = mainPackagePair.second
|
|
15
|
-
mainFile = internalPath(self, mainFile)
|
|
16
|
-
assetSystem = AssetSystem(streams.toMap())
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
buildMode(): Bool
|
|
21
|
-
target node async "return !!self_.buildMode_"
|
|
22
|
-
|
|
23
|
-
setAssets(assetSystem: AssetSystem): Unit
|
|
24
|
-
target node async "self_.assets_ = assetSystem_"
|
|
25
|
-
|
|
26
|
-
packageAssets(): AssetSystem {
|
|
27
|
-
let streams = internalListDirectory(internalPath(self, "."))
|
|
28
|
-
AssetSystem(streams.toMap())
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
dependencyAssets(user: String, package: String): AssetSystem {
|
|
32
|
-
panic("dependencyAssets not yet implemented")
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
arguments(): List[String]
|
|
36
|
-
target node async "return self_.array_"
|
|
37
|
-
|
|
38
|
-
mainTask(): Task
|
|
39
|
-
target js async "return self_.task_"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
let
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
let
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
1
|
+
capability BuildSystem {}
|
|
2
|
+
capability BrowserCode(packageGroup: String, packageName: String, mainFile: Path, assetSystem: AssetSystem)
|
|
3
|
+
capability BrowserBundle(assetSystem: AssetSystem)
|
|
4
|
+
|
|
5
|
+
extend self: BuildSystem {
|
|
6
|
+
|
|
7
|
+
compileForBrowser(mainFile: String): BrowserCode {
|
|
8
|
+
// TODO: Check that the mainFile is in the current package directory
|
|
9
|
+
internalCompile(self, internalPath(self, mainFile), "browser")
|
|
10
|
+
let streams = internalListDirectory(internalPath(self, ".firefly/output/browser"))
|
|
11
|
+
let mainPackagePair = internalMainPackagePair(self)
|
|
12
|
+
BrowserCode(
|
|
13
|
+
packageGroup = mainPackagePair.first
|
|
14
|
+
packageName = mainPackagePair.second
|
|
15
|
+
mainFile = internalPath(self, mainFile)
|
|
16
|
+
assetSystem = AssetSystem(streams.toMap())
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
buildMode(): Bool
|
|
21
|
+
target node async "return !!self_.buildMode_"
|
|
22
|
+
|
|
23
|
+
setAssets(assetSystem: AssetSystem): Unit
|
|
24
|
+
target node async "self_.assets_ = assetSystem_"
|
|
25
|
+
|
|
26
|
+
packageAssets(): AssetSystem {
|
|
27
|
+
let streams = internalListDirectory(internalPath(self, "."))
|
|
28
|
+
AssetSystem(streams.toMap())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
dependencyAssets(user: String, package: String): AssetSystem {
|
|
32
|
+
panic("dependencyAssets not yet implemented")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
arguments(): List[String]
|
|
36
|
+
target node async "return self_.array_"
|
|
37
|
+
|
|
38
|
+
mainTask(): Task
|
|
39
|
+
target js async "return self_.task_"
|
|
40
|
+
|
|
41
|
+
crypto(): Crypto
|
|
42
|
+
target js async "return (typeof globalThis !== 'undefined' ? globalThis : window).crypto"
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
extend self: BrowserCode {
|
|
47
|
+
|
|
48
|
+
assets(): AssetSystem {
|
|
49
|
+
self.assetSystem
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
bundle(minify: Bool = True, sourceMap: Bool = False): BrowserBundle {
|
|
53
|
+
let prefix = ".firefly/output/browser"
|
|
54
|
+
let mainJsBaseFile = self.mainFile.base().removeLast(".ff").grab() + ".mjs"
|
|
55
|
+
let mainJsFile = prefix + "/" + self.packageGroup + "/" + self.packageName + "/" + mainJsBaseFile
|
|
56
|
+
let mainDirectory = self.mainFile.parent().grab()
|
|
57
|
+
let file = prefix + "/Main.bundle.js"
|
|
58
|
+
internalCallEsBuild(self, mainJsFile = mainJsFile, outputPath = file, minify = minify, sourceMap = sourceMap)
|
|
59
|
+
let assets = AssetSystem([
|
|
60
|
+
Pair(file.dropFirst(prefix.size()), {mainDirectory.path(file).readStream()})
|
|
61
|
+
...if(sourceMap) {[
|
|
62
|
+
Pair(file.dropFirst(prefix.size()) + ".map", {mainDirectory.path(file + ".map").readStream()})
|
|
63
|
+
]} else {[]}
|
|
64
|
+
].toMap())
|
|
65
|
+
BrowserBundle(assets)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
extend self: BrowserBundle {
|
|
71
|
+
|
|
72
|
+
assets(): AssetSystem {
|
|
73
|
+
self.assetSystem
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
internalCallEsBuild(
|
|
80
|
+
self: BrowserCode
|
|
81
|
+
mainJsFile: String
|
|
82
|
+
outputPath: String
|
|
83
|
+
minify: Bool
|
|
84
|
+
sourceMap: Bool
|
|
85
|
+
): Unit
|
|
86
|
+
target node async """
|
|
87
|
+
import * as esbuild from 'esbuild'
|
|
88
|
+
return await esbuild.build({
|
|
89
|
+
entryPoints: [mainJsFile_],
|
|
90
|
+
bundle: true,
|
|
91
|
+
minify: minify_,
|
|
92
|
+
sourcemap: sourceMap_,
|
|
93
|
+
platform: 'browser',
|
|
94
|
+
target: 'es6',
|
|
95
|
+
external: ['../../../node_modules/*'], // TODO
|
|
96
|
+
outfile: outputPath_
|
|
97
|
+
})
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
internalNodeCallEsBuild(
|
|
101
|
+
self: NodeSystem
|
|
102
|
+
mainJsFile: String
|
|
103
|
+
outputPath: String
|
|
104
|
+
minify: Bool
|
|
105
|
+
): Unit
|
|
106
|
+
target node async """
|
|
107
|
+
import * as esbuild from 'esbuild'
|
|
108
|
+
return await esbuild.build({
|
|
109
|
+
entryPoints: [mainJsFile_],
|
|
110
|
+
bundle: true,
|
|
111
|
+
minify: minify_,
|
|
112
|
+
sourcemap: true,
|
|
113
|
+
platform: 'node',
|
|
114
|
+
target: 'es6',
|
|
115
|
+
external: ['../../../node_modules/*'], // TODO
|
|
116
|
+
outfile: outputPath_
|
|
117
|
+
})
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
internalListDirectory(path: Path): List[Pair[String, () => Stream[Buffer]]] {
|
|
121
|
+
function go(currentPath: Path): Stream[Path] {
|
|
122
|
+
currentPath.entries().flatMap {file =>
|
|
123
|
+
if(file.isDirectory()) {
|
|
124
|
+
go(file.path())
|
|
125
|
+
} else {
|
|
126
|
+
[file.path()].toStream()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
go(path).map {file =>
|
|
131
|
+
Pair("/" + file.relativeTo(path).replace("\\", "/"), {file.readStream()})
|
|
132
|
+
}.toList()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
internalPath(buildSystem: BuildSystem, absoluteOrRelative: String): Path
|
|
136
|
+
target node async """
|
|
137
|
+
return absoluteOrRelative_
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
internalCompile(buildSystem: BuildSystem, mainFile: Path, target: String): Unit
|
|
141
|
+
target node async """
|
|
142
|
+
return await $firefly_compiler.buildViaBuildSystem_$(buildSystem_, buildSystem_.fireflyPath_, mainFile_, target_, $task)
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
internalMainPackagePair(buildSystem: BuildSystem): Pair[String, String]
|
|
146
|
+
target node async """
|
|
147
|
+
return {first_: buildSystem_.mainPackagePair_.group_, second_: buildSystem_.mainPackagePair_.name_}
|
|
148
|
+
"""
|
package/core/Crypto.ff
CHANGED
|
@@ -1,95 +1,96 @@
|
|
|
1
|
-
capability Crypto {}
|
|
2
|
-
|
|
3
|
-
extend self: Crypto {
|
|
4
|
-
|
|
5
|
-
randomUuid(): String
|
|
6
|
-
target js async """
|
|
7
|
-
return self_.randomUUID();
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
randomBuffer(size: Int): Buffer {
|
|
11
|
-
let buffer = Buffer.new(size)
|
|
12
|
-
self.randomizeBuffer(buffer)
|
|
13
|
-
buffer
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
randomizeBuffer(buffer: Buffer): Unit
|
|
17
|
-
target js async """
|
|
18
|
-
self_.getRandomValues(new Uint8Array(buffer_.buffer, buffer_.byteOffset, buffer_.byteLength));
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
hmacSha256(key: Buffer, buffer: Buffer): Buffer
|
|
22
|
-
target js async """
|
|
23
|
-
const cryptoKey = await self_.subtle.importKey(
|
|
24
|
-
'raw',
|
|
25
|
-
key_,
|
|
26
|
-
{name: 'HMAC', hash: {name: 'SHA-256'}},
|
|
27
|
-
false,
|
|
28
|
-
['sign']
|
|
29
|
-
);
|
|
30
|
-
const signature = await self_.subtle.sign(
|
|
31
|
-
'HMAC',
|
|
32
|
-
cryptoKey,
|
|
33
|
-
buffer_
|
|
34
|
-
);
|
|
35
|
-
return new DataView(signature);
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
sha256(buffer: Buffer): Buffer
|
|
39
|
-
target js async """
|
|
40
|
-
let hash = await self_.subtle.digest('SHA-256', buffer_);
|
|
41
|
-
return new DataView(hash);
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
let salt = self.randomBuffer(16)
|
|
46
|
-
let hash =
|
|
47
|
-
"
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
passwordHash.split('
|
|
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
|
-
|
|
1
|
+
capability Crypto {}
|
|
2
|
+
|
|
3
|
+
extend self: Crypto {
|
|
4
|
+
|
|
5
|
+
randomUuid(): String
|
|
6
|
+
target js async """
|
|
7
|
+
return self_.randomUUID();
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
randomBuffer(size: Int): Buffer {
|
|
11
|
+
let buffer = Buffer.new(size)
|
|
12
|
+
self.randomizeBuffer(buffer)
|
|
13
|
+
buffer
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
randomizeBuffer(buffer: Buffer): Unit
|
|
17
|
+
target js async """
|
|
18
|
+
self_.getRandomValues(new Uint8Array(buffer_.buffer, buffer_.byteOffset, buffer_.byteLength));
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
hmacSha256(key: Buffer, buffer: Buffer): Buffer
|
|
22
|
+
target js async """
|
|
23
|
+
const cryptoKey = await self_.subtle.importKey(
|
|
24
|
+
'raw',
|
|
25
|
+
key_,
|
|
26
|
+
{name: 'HMAC', hash: {name: 'SHA-256'}},
|
|
27
|
+
false,
|
|
28
|
+
['sign']
|
|
29
|
+
);
|
|
30
|
+
const signature = await self_.subtle.sign(
|
|
31
|
+
'HMAC',
|
|
32
|
+
cryptoKey,
|
|
33
|
+
buffer_
|
|
34
|
+
);
|
|
35
|
+
return new DataView(signature);
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
sha256(buffer: Buffer): Buffer
|
|
39
|
+
target js async """
|
|
40
|
+
let hash = await self_.subtle.digest('SHA-256', buffer_);
|
|
41
|
+
return new DataView(hash);
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
hashPassword(password: String, iterations: Int = 600000): String {
|
|
45
|
+
let salt = self.randomBuffer(16)
|
|
46
|
+
let hash = internalHashPassword(self, salt, password.toBuffer(), iterations)
|
|
47
|
+
"$pbkdf2-sha256-hex$" + iterations + "$" + salt.toHex() + "$" + hash.toHex()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
checkPassword(password: String, passwordHash: String): Bool {
|
|
51
|
+
passwordHash.split('$').{
|
|
52
|
+
| ["", "pbkdf2-sha256-hex", iterationsText, saltText, hashText] {
|
|
53
|
+
iterationsText.getInt() | Some(iterations)
|
|
54
|
+
} =>
|
|
55
|
+
let computedHash =
|
|
56
|
+
internalHashPassword(self, Buffer.fromHex(saltText), password.toBuffer(), iterations)
|
|
57
|
+
let hash = Buffer.fromHex(hashText)
|
|
58
|
+
self.constantTimeEquals(computedHash, hash)
|
|
59
|
+
| _ => False
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
constantTimeEquals(buffer1: Buffer, buffer2: Buffer): Bool {
|
|
64
|
+
if(buffer1.size() != buffer2.size()) {False} else:
|
|
65
|
+
mutable v = 0
|
|
66
|
+
mutable i = 0
|
|
67
|
+
while {i < buffer1.size()} {
|
|
68
|
+
v = v.bitOr(buffer1.grabUint8(i).bitXor(buffer2.grabUint8(i)))
|
|
69
|
+
i += 1
|
|
70
|
+
}
|
|
71
|
+
v == 0
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
internalHashPassword(system: Crypto, salt: Buffer, password: Buffer, iterations: Int): Buffer
|
|
77
|
+
target js async """
|
|
78
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
79
|
+
'raw',
|
|
80
|
+
password_,
|
|
81
|
+
{name: 'PBKDF2'},
|
|
82
|
+
false,
|
|
83
|
+
['deriveBits']
|
|
84
|
+
);
|
|
85
|
+
const hashBuffer = await crypto.subtle.deriveBits(
|
|
86
|
+
{
|
|
87
|
+
name: 'PBKDF2',
|
|
88
|
+
salt: salt_,
|
|
89
|
+
iterations: iterations_,
|
|
90
|
+
hash: 'SHA-256'
|
|
91
|
+
},
|
|
92
|
+
keyMaterial,
|
|
93
|
+
256
|
|
94
|
+
);
|
|
95
|
+
return new DataView(hashBuffer);
|
|
96
|
+
"""
|