firefly-compiler 0.4.50 → 0.4.52

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.
Files changed (109) hide show
  1. package/.hintrc +4 -4
  2. package/.vscode/settings.json +4 -4
  3. package/bin/Release.ff +153 -155
  4. package/bin/firefly.mjs +1 -1
  5. package/compiler/Builder.ff +257 -257
  6. package/compiler/Compiler.ff +227 -227
  7. package/compiler/Dependencies.ff +186 -186
  8. package/compiler/DependencyLock.ff +17 -17
  9. package/compiler/JsEmitter.ff +946 -946
  10. package/compiler/LspHook.ff +202 -202
  11. package/compiler/ModuleCache.ff +178 -178
  12. package/compiler/Workspace.ff +88 -88
  13. package/core/.firefly/include/package-lock.json +394 -394
  14. package/core/.firefly/include/package.json +5 -5
  15. package/core/.firefly/include/prepare.sh +1 -1
  16. package/core/.firefly/package.ff +2 -2
  17. package/core/Array.ff +265 -265
  18. package/core/Atomic.ff +64 -64
  19. package/core/Box.ff +7 -7
  20. package/core/BrowserSystem.ff +40 -40
  21. package/core/BuildSystem.ff +148 -148
  22. package/core/Crypto.ff +96 -96
  23. package/core/Equal.ff +36 -36
  24. package/core/HttpClient.ff +87 -87
  25. package/core/JsSystem.ff +69 -69
  26. package/core/Json.ff +434 -434
  27. package/core/List.ff +486 -486
  28. package/core/Lock.ff +144 -144
  29. package/core/NodeSystem.ff +195 -189
  30. package/core/Ordering.ff +161 -161
  31. package/core/Path.ff +401 -401
  32. package/core/Random.ff +134 -134
  33. package/core/RbMap.ff +216 -216
  34. package/core/Show.ff +43 -43
  35. package/core/SourceLocation.ff +68 -68
  36. package/core/Task.ff +141 -141
  37. package/experimental/benchmarks/ListGrab.ff +23 -23
  38. package/experimental/benchmarks/ListGrab.java +55 -55
  39. package/experimental/benchmarks/Pyrotek45.ff +30 -30
  40. package/experimental/benchmarks/Pyrotek45.java +64 -64
  41. package/experimental/bidirectional/Bidi.ff +88 -88
  42. package/experimental/random/Index.ff +53 -53
  43. package/experimental/random/Process.ff +120 -120
  44. package/experimental/random/Scrape.ff +51 -51
  45. package/experimental/random/Symbols.ff +73 -73
  46. package/experimental/random/Tensor.ff +52 -52
  47. package/experimental/random/Units.ff +36 -36
  48. package/experimental/s3/S3TestAuthorizationHeader.ff +38 -38
  49. package/experimental/s3/S3TestPut.ff +15 -15
  50. package/experimental/tests/TestJson.ff +26 -26
  51. package/firefly.sh +0 -0
  52. package/fireflysite/Main.ff +13 -13
  53. package/lsp/.firefly/package.ff +1 -1
  54. package/lsp/CompletionHandler.ff +808 -808
  55. package/lsp/Handler.ff +714 -714
  56. package/lsp/HoverHandler.ff +79 -79
  57. package/lsp/LanguageServer.ff +272 -272
  58. package/lsp/SignatureHelpHandler.ff +55 -55
  59. package/lsp/SymbolHandler.ff +181 -181
  60. package/lsp/TestReferences.ff +16 -16
  61. package/lsp/TestReferencesCase.ff +7 -7
  62. package/lsp/stderr.txt +1 -1
  63. package/lsp/stdin.txt +10 -10
  64. package/lsp/stdout.txt +40 -40
  65. package/lux/.firefly/package.ff +1 -1
  66. package/lux/Css.ff +648 -648
  67. package/lux/CssTest.ff +48 -48
  68. package/lux/Lux.ff +487 -487
  69. package/lux/LuxEvent.ff +116 -116
  70. package/lux/Main.ff +128 -128
  71. package/lux/Main2.ff +144 -144
  72. package/output/js/ff/compiler/Builder.mjs +43 -43
  73. package/output/js/ff/compiler/Dependencies.mjs +3 -3
  74. package/output/js/ff/core/Array.mjs +59 -59
  75. package/output/js/ff/core/Atomic.mjs +36 -36
  76. package/output/js/ff/core/BrowserSystem.mjs +11 -11
  77. package/output/js/ff/core/BuildSystem.mjs +30 -30
  78. package/output/js/ff/core/Crypto.mjs +40 -40
  79. package/output/js/ff/core/HttpClient.mjs +24 -24
  80. package/output/js/ff/core/Json.mjs +147 -147
  81. package/output/js/ff/core/List.mjs +50 -50
  82. package/output/js/ff/core/Lock.mjs +97 -97
  83. package/output/js/ff/core/NodeSystem.mjs +83 -77
  84. package/output/js/ff/core/Ordering.mjs +8 -8
  85. package/output/js/ff/core/Path.mjs +231 -231
  86. package/output/js/ff/core/Random.mjs +56 -56
  87. package/output/js/ff/core/Task.mjs +31 -31
  88. package/package.json +1 -1
  89. package/rpc/.firefly/package.ff +1 -1
  90. package/rpc/Rpc.ff +69 -69
  91. package/s3/.firefly/package.ff +1 -1
  92. package/s3/S3.ff +90 -93
  93. package/unsafejs/UnsafeJs.ff +19 -19
  94. package/vscode/LICENSE.txt +21 -21
  95. package/vscode/Prepublish.ff +15 -15
  96. package/vscode/README.md +16 -16
  97. package/vscode/client/package.json +22 -22
  98. package/vscode/client/src/extension.ts +104 -104
  99. package/vscode/icons/firefly-icon.svg +10 -10
  100. package/vscode/language-configuration.json +61 -61
  101. package/vscode/package-lock.json +3623 -3623
  102. package/vscode/package.json +1 -1
  103. package/vscode/snippets.json +241 -241
  104. package/webserver/.firefly/include/package-lock.json +16 -16
  105. package/webserver/.firefly/include/package.json +5 -5
  106. package/webserver/.firefly/package.ff +2 -2
  107. package/webserver/WebServer.ff +685 -685
  108. package/websocket/.firefly/package.ff +1 -1
  109. package/websocket/WebSocket.ff +131 -131
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
+ }
@@ -1,40 +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
- 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
- }
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
+ }
@@ -1,148 +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
- 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
- """
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,96 +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
- 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
- """
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
+ """
package/core/Equal.ff CHANGED
@@ -1,36 +1,36 @@
1
- trait T: Equal {
2
- equals(x: T, y: T): Bool
3
- }
4
-
5
- notEquals[T: Equal](x: T, y: T): Bool {
6
- !equals(x, y)
7
- }
8
-
9
- instance Nothing: Equal {
10
- equals(x: Nothing, y: Nothing): Bool {True}
11
- }
12
-
13
- instance Bool: Equal {
14
- equals(x: Bool, y: Bool): Bool
15
- target js sync """return x_ === y_"""
16
- }
17
-
18
- instance Char: Equal {
19
- equals(x: Char, y: Char): Bool
20
- target js sync """return x_ === y_"""
21
- }
22
-
23
- instance Int: Equal {
24
- equals(x: Int, y: Int): Bool
25
- target js sync """return x_ === y_"""
26
- }
27
-
28
- instance Float: Equal {
29
- equals(x: Float, y: Float): Bool
30
- target js sync """return x_ === y_"""
31
- }
32
-
33
- instance String: Equal {
34
- equals(x: String, y: String): Bool
35
- target js sync """return x_ === y_"""
36
- }
1
+ trait T: Equal {
2
+ equals(x: T, y: T): Bool
3
+ }
4
+
5
+ notEquals[T: Equal](x: T, y: T): Bool {
6
+ !equals(x, y)
7
+ }
8
+
9
+ instance Nothing: Equal {
10
+ equals(x: Nothing, y: Nothing): Bool {True}
11
+ }
12
+
13
+ instance Bool: Equal {
14
+ equals(x: Bool, y: Bool): Bool
15
+ target js sync """return x_ === y_"""
16
+ }
17
+
18
+ instance Char: Equal {
19
+ equals(x: Char, y: Char): Bool
20
+ target js sync """return x_ === y_"""
21
+ }
22
+
23
+ instance Int: Equal {
24
+ equals(x: Int, y: Int): Bool
25
+ target js sync """return x_ === y_"""
26
+ }
27
+
28
+ instance Float: Equal {
29
+ equals(x: Float, y: Float): Bool
30
+ target js sync """return x_ === y_"""
31
+ }
32
+
33
+ instance String: Equal {
34
+ equals(x: String, y: String): Bool
35
+ target js sync """return x_ === y_"""
36
+ }