firefly-compiler 0.4.36 → 0.4.40

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/bin/Release.ff CHANGED
@@ -1,12 +1,28 @@
1
+ dependency ff:s3:0.0.0
2
+ import S3 from ff:s3
3
+
1
4
  nodeMain(system: NodeSystem) {
2
- run(system, "node", ["output/js/ff/compiler/Main.mjs", "bootstrap"], system.path(".."))
3
- run(system, "node", ["output/js/ff/compiler/Main.mjs", "bootstrap"], system.path(".."))
4
- run(system, "node", ["output/js/ff/compiler/Main.mjs", "bootstrap"], system.path(".."))
5
- bumpMinorVersion(system, system.path("../package.json"))
6
- bumpMinorVersion(system, system.path("../vscode/package.json"))
7
- run(system, "npm", ["publish"], system.path(".."))
8
- run(system, "vsce", ["publish"], system.path("../vscode"))
9
- // tar gz core etc. and upload to s3
5
+ system.arguments().{
6
+ | [] =>
7
+ | [awsUser, awsKey] =>
8
+ run(system, "node", ["output/js/ff/compiler/Main.mjs", "bootstrap"], system.path(".."))
9
+ run(system, "node", ["output/js/ff/compiler/Main.mjs", "bootstrap"], system.path(".."))
10
+ run(system, "node", ["output/js/ff/compiler/Main.mjs", "bootstrap"], system.path(".."))
11
+ bumpMinorVersion(system, system.path("../package.json"))
12
+ bumpMinorVersion(system, system.path("../vscode/package.json"))
13
+ //run(system, "npm", ["publish"], system.path(".."))
14
+ //run(system, "vsce", ["publish"], system.path("../vscode"))
15
+ let coreTemporary = system.path("../core/.firefly/temporary")
16
+ if(!coreTemporary.exists()) {coreTemporary.createDirectory()}
17
+ let coreTarGz = coreTemporary.slash("ff_core_0_0_0.tar.gz")
18
+ if(coreTarGz.exists()) {
19
+ coreTarGz.delete()
20
+ system.writeLine("Deleted " + coreTarGz.absolute())
21
+ }
22
+ internalMakeTarGz(coreTarGz, system.path("../core"))
23
+ system.writeLine("Created " + coreTarGz.absolute())
24
+ //S3.put(system, awsUser, awsKey, )
25
+ }
10
26
  }
11
27
 
12
28
  run(system: NodeSystem, command: String, arguments: List[String], workingDirectory: Path) {
@@ -47,3 +63,9 @@ bumpMinorVersion(system: NodeSystem, packageJsonPath: Path) {
47
63
  }
48
64
  packageJsonPath.writeText(newContent)
49
65
  }
66
+
67
+ internalMakeTarGz(tarGzPath: Path, path: Path): Unit
68
+ target node async """
69
+ import * as tar from 'tar'
70
+ await tar.create({gzip: true, file: tarGzPath_}, [path_]);
71
+ """
@@ -8,6 +8,9 @@ extend self: BrowserSystem {
8
8
  mainTask(): Task
9
9
  target js async "return self_.task_"
10
10
 
11
+ crypto(): Crypto
12
+ target js async "return (typeof globalThis !== 'undefined' ? globalThis : window).crypto"
13
+
11
14
  js(): JsSystem
12
15
  target js async "return typeof globalThis !== 'undefined' ? globalThis : window"
13
16
 
package/core/Buffer.ff CHANGED
@@ -143,10 +143,10 @@ extend self: Buffer {
143
143
 
144
144
  }
145
145
 
146
- fromByteArray(array: List[Int]): Buffer
146
+ fromByteList(array: List[Int]): Buffer
147
147
  target js sync "return new DataView(new Uint8Array(array_).buffer)"
148
148
 
149
- fromBufferArray(array: List[Buffer]): Buffer
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 = hexString.match(/.{1,2}/g) || []
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
  """
@@ -38,6 +38,9 @@ extend self: BuildSystem {
38
38
  mainTask(): Task
39
39
  target js async "return self_.task_"
40
40
 
41
+ crypto(): Crypto
42
+ target js async "return (typeof globalThis !== 'undefined' ? globalThis : window).crypto"
43
+
41
44
  }
42
45
 
43
46
  extend self: BrowserCode {
package/core/Crypto.ff CHANGED
@@ -41,44 +41,54 @@ extend self: Crypto {
41
41
  return new DataView(hash);
42
42
  """
43
43
 
44
- makePasswordHash(password: String, iterations: Int = 100000): String {
44
+ hashPassword(password: String, iterations: Int = 600000, pepper: String = ""): String {
45
45
  let salt = self.randomBuffer(16)
46
- let hash = internalMakePasswordHash(salt, password.toBuffer(), iterations)
47
- "PSG_" + iterations + "_" + salt.toHex() + "_" + hash.toHex()
46
+ let hash = internalHashPassword(self, salt, (password + pepper).toBuffer(), iterations)
47
+ "$pbkdf2-sha256$" + iterations + "$" + salt.toHex() + "$" + hash.toHex()
48
48
  }
49
49
 
50
- checkPasswordHash(password: String, passwordHash: String): Bool {
51
- passwordHash.split('_').{
52
- | ["PSG", iterationsText, saltText, hashText] {iterationsText.getInt() | Some(iterations)} =>
53
- let computedHash = internalMakePasswordHash(Buffer.fromHex(saltText), password.toBuffer(), iterations)
50
+ checkPassword(
51
+ password: String,
52
+ passwordHash: String,
53
+ pepper: String = "",
54
+ minIterations: Int = 100000,
55
+ maxIterations: Int = 2000000
56
+ ): Bool {
57
+ passwordHash.split('$').{
58
+ | ["", "pbkdf2-sha256", iterationsText, saltText, hashText] {iterationsText.getInt() | Some(iterations)} {
59
+ iterations >= minIterations && iterations <= maxIterations
60
+ } =>
61
+ let computedHash =
62
+ internalHashPassword(self, Buffer.fromHex(saltText), (password + pepper).toBuffer(), iterations)
54
63
  let hash = Buffer.fromHex(hashText)
55
64
  self.constantTimeEquals(computedHash, hash)
56
65
  | _ => False
57
66
  }
58
67
  }
59
-
68
+
60
69
  constantTimeEquals(buffer1: Buffer, buffer2: Buffer): Bool {
61
70
  if(buffer1.size() != buffer2.size()) {False} else:
62
71
  mutable v = 0
63
72
  mutable i = 0
64
73
  while {i < buffer1.size()} {
65
- v = v.bitOr(buffer1.grabUint8(i).bitXor(buffer2.grabUint8(i)))
74
+ v = v.bitOr(buffer1.grabUint8(i).bitXor(buffer2.grabUint8(i)))
75
+ i += 1
66
76
  }
67
77
  v == 0
68
78
  }
69
79
 
70
80
  }
71
81
 
72
- internalMakePasswordHash(salt: Buffer, password: Buffer, iterations: Int): Buffer
82
+ internalHashPassword(system: Crypto, salt: Buffer, password: Buffer, iterations: Int): Buffer
73
83
  target js async """
74
84
  const keyMaterial = await crypto.subtle.importKey(
75
85
  'raw',
76
86
  password_,
77
87
  {name: 'PBKDF2'},
78
88
  false,
79
- ['deriveKey']
89
+ ['deriveBits']
80
90
  );
81
- const derivedKey = await crypto.subtle.deriveKey(
91
+ const hashBuffer = await crypto.subtle.deriveBits(
82
92
  {
83
93
  name: 'PBKDF2',
84
94
  salt: salt_,
@@ -86,10 +96,7 @@ internalMakePasswordHash(salt: Buffer, password: Buffer, iterations: Int): Buffe
86
96
  hash: 'SHA-256'
87
97
  },
88
98
  keyMaterial,
89
- {name: 'AES-GCM', length: 256},
90
- true,
91
- ['encrypt', 'decrypt']
99
+ 256
92
100
  );
93
- const hashBuffer = await crypto.subtle.exportKey('raw', derivedKey);
94
101
  return new DataView(hashBuffer);
95
102
  """
package/core/Instant.ff CHANGED
@@ -1,9 +1,26 @@
1
1
  newtype Instant(since1970: Duration)
2
2
 
3
+ fromIso(date: String): Option[Instant] {
4
+ let zone = date.endsWith("Z") || date.contains("+") || date.dropWhile {_ != 'T'}.contains("-")
5
+ if(zone && date.takeWhile {_ != 'T'}.contains("-") && date.contains("T") && date.contains(":")) {
6
+ internalParseDate(date)
7
+ }
8
+ }
9
+
3
10
  extend self: Instant {
4
11
 
5
12
  add(duration: Duration): Instant {
6
13
  Instant(Duration(self.since1970.seconds + duration.seconds))
7
14
  }
15
+
16
+ toIso(): String
17
+ target js sync """
18
+ return new Date(self_ * 1000).toISOString();
19
+ """
8
20
 
9
21
  }
22
+
23
+ internalParseDate(date: String): Instant
24
+ target js sync """
25
+ return Date.parse(date_) * 0.001;
26
+ """
@@ -45,7 +45,7 @@ extend self: NodeSystem {
45
45
  mainTask(): Task
46
46
  target js async "return self_.task_"
47
47
 
48
- crypto()
48
+ crypto(): Crypto
49
49
  target js async "return (typeof globalThis !== 'undefined' ? globalThis : window).crypto"
50
50
 
51
51
  js(): JsSystem
package/core/Stream.ff CHANGED
@@ -372,7 +372,7 @@ extend self: Stream[Buffer] {
372
372
  toBuffer(): Buffer {
373
373
  let builder = Array.new()
374
374
  self.each {builder.push(_)}
375
- Buffer.fromBufferArray(builder.drain())
375
+ Buffer.fromBufferList(builder.drain())
376
376
  }
377
377
 
378
378
  toString(encoding: String = "utf8"): String {
@@ -1,12 +1,12 @@
1
1
  main(system: NodeSystem) {
2
- let inBuffers = 1.to(100).map {_ => Buffer.fromByteArray([5, 5, 3, 1, 2].toArray())}
2
+ let inBuffers = 1.to(100).map {_ => Buffer.fromByteList([5, 5, 3, 1, 2].toArray())}
3
3
  let inStream = inBuffers.toStream()
4
4
  let outStream = toRunLength(inStream, 3)
5
5
  printRunLength(outStream)
6
6
  }
7
7
 
8
8
  printRunLength(outStream: Stream[Buffer]) {
9
- let buffer = Buffer.fromBufferArray(outStream.toArray())
9
+ let buffer = Buffer.fromBufferList(outStream.toArray())
10
10
  Log.debug(buffer.toHex())
11
11
  let stack = Stack.make()
12
12
  mutable i = 0
@@ -14,7 +14,7 @@ printRunLength(outStream: Stream[Buffer]) {
14
14
  1.to(buffer.grabUint8(i)).each {_ => stack.push(buffer.grabUint8(i + 1))}
15
15
  i += 2
16
16
  }
17
- Log.debug(Buffer.fromByteArray(stack.drain()).toHex())
17
+ Log.debug(Buffer.fromByteList(stack.drain()).toHex())
18
18
  }
19
19
 
20
20
  toRunLength(stream: Stream[Buffer], bufferSize: Int = 65536): Stream[Buffer] {
@@ -158,7 +158,7 @@ parseRequestHeaders(input: Stream[Buffer]): Pair[Map[String, String], Stream[Buf
158
158
  offset += 1
159
159
  }
160
160
  buffers.push(buffer.view(0, offset))
161
- let headers = Buffer.fromBufferArray(buffers.drain()).toString()
161
+ let headers = Buffer.fromBufferList(buffers.drain()).toString()
162
162
  let map = headers.lines().pairs().filter {_.second.size() != 0}.map {| Pair(i, line) =>
163
163
  line.splitFirst(':').else {
164
164
  throw(BadRequestException("Invalid header at line " + i + " '" + line + "'"))
@@ -173,7 +173,7 @@ parseRequestBody(contentLength: Int, input: Stream[Buffer]): Pair[Json, Stream[B
173
173
  } catchAny {error =>
174
174
  throw(BadRequestException("End of input while parsing request body"))
175
175
  } grab()
176
- let body = Buffer.fromBufferArray(bodyPair.first).toString()
176
+ let body = Buffer.fromBufferList(bodyPair.first).toString()
177
177
  let json = Json.read(body).else {
178
178
  throw(BadRequestException("Invalid JSON in request body: " + body))
179
179
  }
@@ -107,6 +107,10 @@ export function BrowserSystem_mainTask(self_) {
107
107
  throw new Error('Function BrowserSystem_mainTask is missing on this target in sync context.');
108
108
  }
109
109
 
110
+ export function BrowserSystem_crypto(self_) {
111
+ throw new Error('Function BrowserSystem_crypto is missing on this target in sync context.');
112
+ }
113
+
110
114
  export function BrowserSystem_js(self_) {
111
115
  throw new Error('Function BrowserSystem_js is missing on this target in sync context.');
112
116
  }
@@ -135,6 +139,10 @@ export async function BrowserSystem_mainTask$(self_, $task) {
135
139
  return self_.task_
136
140
  }
137
141
 
142
+ export async function BrowserSystem_crypto$(self_, $task) {
143
+ return (typeof globalThis !== 'undefined' ? globalThis : window).crypto
144
+ }
145
+
138
146
  export async function BrowserSystem_js$(self_, $task) {
139
147
  return typeof globalThis !== 'undefined' ? globalThis : window
140
148
  }
@@ -99,11 +99,11 @@ export function new_(size_, shared_ = false) {
99
99
  return new DataView(shared_ ? new SharedArrayBuffer(size_) : new ArrayBuffer(size_))
100
100
  }
101
101
 
102
- export function fromByteArray_(array_) {
102
+ export function fromByteList_(array_) {
103
103
  return new DataView(new Uint8Array(array_).buffer)
104
104
  }
105
105
 
106
- export function fromBufferArray_(array_) {
106
+ export function fromBufferList_(array_) {
107
107
 
108
108
  let length = 0
109
109
  for(let b of array_) length += b.byteLength
@@ -120,7 +120,7 @@ export function fromBufferArray_(array_) {
120
120
 
121
121
  export function fromHex_(hex_) {
122
122
 
123
- const hexValues = hexString.match(/.{1,2}/g) || []
123
+ const hexValues = hex_.match(/.{1,2}/g) || []
124
124
  const numbers = hexValues.map(value => parseInt(value, 16))
125
125
  return new DataView(new Uint8Array(numbers).buffer)
126
126
 
@@ -139,12 +139,12 @@ export async function new_$(size_, shared_ = false, $task) {
139
139
  throw new Error('Function new is missing on this target in async context.');
140
140
  }
141
141
 
142
- export async function fromByteArray_$(array_, $task) {
143
- throw new Error('Function fromByteArray is missing on this target in async context.');
142
+ export async function fromByteList_$(array_, $task) {
143
+ throw new Error('Function fromByteList is missing on this target in async context.');
144
144
  }
145
145
 
146
- export async function fromBufferArray_$(array_, $task) {
147
- throw new Error('Function fromBufferArray is missing on this target in async context.');
146
+ export async function fromBufferList_$(array_, $task) {
147
+ throw new Error('Function fromBufferList is missing on this target in async context.');
148
148
  }
149
149
 
150
150
  export async function fromHex_$(hex_, $task) {
@@ -241,6 +241,10 @@ export function BuildSystem_mainTask(self_) {
241
241
  throw new Error('Function BuildSystem_mainTask is missing on this target in sync context.');
242
242
  }
243
243
 
244
+ export function BuildSystem_crypto(self_) {
245
+ throw new Error('Function BuildSystem_crypto is missing on this target in sync context.');
246
+ }
247
+
244
248
  export async function BuildSystem_compileForBrowser$(self_, mainFile_, $task) {
245
249
  (await ff_core_BuildSystem.internalCompile_$(self_, (await ff_core_BuildSystem.internalPath_$(self_, mainFile_, $task)), "browser", $task));
246
250
  const streams_ = (await ff_core_BuildSystem.internalListDirectory_$((await ff_core_BuildSystem.internalPath_$(self_, ".firefly/output/browser", $task)), $task));
@@ -273,6 +277,10 @@ export async function BuildSystem_mainTask$(self_, $task) {
273
277
  return self_.task_
274
278
  }
275
279
 
280
+ export async function BuildSystem_crypto$(self_, $task) {
281
+ return (typeof globalThis !== 'undefined' ? globalThis : window).crypto
282
+ }
283
+
276
284
  export function BrowserCode_assets(self_) {
277
285
  return self_.assetSystem_
278
286
  }
@@ -95,20 +95,20 @@ import * as ff_core_Unit from "../../ff/core/Unit.mjs"
95
95
 
96
96
 
97
97
 
98
- export function internalMakePasswordHash_(salt_, password_, iterations_) {
99
- throw new Error('Function internalMakePasswordHash is missing on this target in sync context.');
98
+ export function internalHashPassword_(system_, salt_, password_, iterations_) {
99
+ throw new Error('Function internalHashPassword is missing on this target in sync context.');
100
100
  }
101
101
 
102
- export async function internalMakePasswordHash_$(salt_, password_, iterations_, $task) {
102
+ export async function internalHashPassword_$(system_, salt_, password_, iterations_, $task) {
103
103
 
104
104
  const keyMaterial = await crypto.subtle.importKey(
105
105
  'raw',
106
106
  password_,
107
107
  {name: 'PBKDF2'},
108
108
  false,
109
- ['deriveKey']
109
+ ['deriveBits']
110
110
  );
111
- const derivedKey = await crypto.subtle.deriveKey(
111
+ const hashBuffer = await crypto.subtle.deriveBits(
112
112
  {
113
113
  name: 'PBKDF2',
114
114
  salt: salt_,
@@ -116,11 +116,8 @@ export async function internalMakePasswordHash_$(salt_, password_, iterations_,
116
116
  hash: 'SHA-256'
117
117
  },
118
118
  keyMaterial,
119
- {name: 'AES-GCM', length: 256},
120
- true,
121
- ['encrypt', 'decrypt']
119
+ 256
122
120
  );
123
- const hashBuffer = await crypto.subtle.exportKey('raw', derivedKey);
124
121
  return new DataView(hashBuffer);
125
122
 
126
123
  }
@@ -147,27 +144,29 @@ export function Crypto_sha256(self_, buffer_) {
147
144
  throw new Error('Function Crypto_sha256 is missing on this target in sync context.');
148
145
  }
149
146
 
150
- export function Crypto_makePasswordHash(self_, password_, iterations_ = 100000) {
147
+ export function Crypto_hashPassword(self_, password_, iterations_ = 600000, pepper_ = "") {
151
148
  const salt_ = ff_core_Crypto.Crypto_randomBuffer(self_, 16);
152
- const hash_ = ff_core_Crypto.internalMakePasswordHash_(salt_, ff_core_String.String_toBuffer(password_), iterations_);
153
- return ((((("PSG_" + iterations_) + "_") + ff_core_Buffer.Buffer_toHex(salt_)) + "_") + ff_core_Buffer.Buffer_toHex(hash_))
149
+ const hash_ = ff_core_Crypto.internalHashPassword_(self_, salt_, ff_core_String.String_toBuffer((password_ + pepper_)), iterations_);
150
+ return ((((("$pbkdf2-sha256$" + iterations_) + "$") + ff_core_Buffer.Buffer_toHex(salt_)) + "$") + ff_core_Buffer.Buffer_toHex(hash_))
154
151
  }
155
152
 
156
- export function Crypto_checkPasswordHash(self_, password_, passwordHash_) {
153
+ export function Crypto_checkPassword(self_, password_, passwordHash_, pepper_ = "", minIterations_ = 100000, maxIterations_ = 2000000) {
157
154
  {
158
- const _1 = ff_core_String.String_split(passwordHash_, 95);
159
- if(_1.length === 4 && _1[0] === "PSG") {
160
- const iterationsText_ = _1[1];
161
- const saltText_ = _1[2];
162
- const hashText_ = _1[3];
163
- const _guard1 = ff_core_String.String_getInt(iterationsText_);
164
- if(_guard1.Some) {
165
- const iterations_ = _guard1.value_;
166
- const computedHash_ = ff_core_Crypto.internalMakePasswordHash_(ff_core_Buffer.fromHex_(saltText_), ff_core_String.String_toBuffer(password_), iterations_);
155
+ const _1 = ff_core_String.String_split(passwordHash_, 36);
156
+ if(_1.length === 5 && _1[0] === "" && _1[1] === "pbkdf2-sha256") {
157
+ const iterationsText_ = _1[2];
158
+ const saltText_ = _1[3];
159
+ const hashText_ = _1[4];
160
+ const _guard2 = ff_core_String.String_getInt(iterationsText_);
161
+ if(_guard2.Some) {
162
+ const iterations_ = _guard2.value_;
163
+ if(((iterations_ >= minIterations_) && (iterations_ <= maxIterations_))) {
164
+ const computedHash_ = ff_core_Crypto.internalHashPassword_(self_, ff_core_Buffer.fromHex_(saltText_), ff_core_String.String_toBuffer((password_ + pepper_)), iterations_);
167
165
  const hash_ = ff_core_Buffer.fromHex_(hashText_);
168
166
  return ff_core_Crypto.Crypto_constantTimeEquals(self_, computedHash_, hash_)
169
167
  }
170
168
  }
169
+ }
171
170
  {
172
171
  return false
173
172
  }
@@ -181,7 +180,8 @@ return false
181
180
  let v_ = 0;
182
181
  let i_ = 0;
183
182
  while((i_ < ff_core_Buffer.Buffer_size(buffer1_))) {
184
- v_ = ff_core_Int.Int_bitOr(v_, ff_core_Int.Int_bitXor(ff_core_Buffer.Buffer_grabUint8(buffer1_, i_), ff_core_Buffer.Buffer_grabUint8(buffer2_, i_)))
183
+ v_ = ff_core_Int.Int_bitOr(v_, ff_core_Int.Int_bitXor(ff_core_Buffer.Buffer_grabUint8(buffer1_, i_), ff_core_Buffer.Buffer_grabUint8(buffer2_, i_)));
184
+ i_ += 1
185
185
  };
186
186
  return (v_ === 0)
187
187
  }
@@ -230,27 +230,29 @@ export async function Crypto_sha256$(self_, buffer_, $task) {
230
230
 
231
231
  }
232
232
 
233
- export async function Crypto_makePasswordHash$(self_, password_, iterations_ = 100000, $task) {
233
+ export async function Crypto_hashPassword$(self_, password_, iterations_ = 600000, pepper_ = "", $task) {
234
234
  const salt_ = (await ff_core_Crypto.Crypto_randomBuffer$(self_, 16, $task));
235
- const hash_ = ff_core_Crypto.internalMakePasswordHash_(salt_, ff_core_String.String_toBuffer(password_), iterations_);
236
- return ((((("PSG_" + iterations_) + "_") + ff_core_Buffer.Buffer_toHex(salt_)) + "_") + ff_core_Buffer.Buffer_toHex(hash_))
235
+ const hash_ = (await ff_core_Crypto.internalHashPassword_$(self_, salt_, ff_core_String.String_toBuffer((password_ + pepper_)), iterations_, $task));
236
+ return ((((("$pbkdf2-sha256$" + iterations_) + "$") + ff_core_Buffer.Buffer_toHex(salt_)) + "$") + ff_core_Buffer.Buffer_toHex(hash_))
237
237
  }
238
238
 
239
- export async function Crypto_checkPasswordHash$(self_, password_, passwordHash_, $task) {
239
+ export async function Crypto_checkPassword$(self_, password_, passwordHash_, pepper_ = "", minIterations_ = 100000, maxIterations_ = 2000000, $task) {
240
240
  {
241
- const _1 = ff_core_String.String_split(passwordHash_, 95);
242
- if(_1.length === 4 && _1[0] === "PSG") {
243
- const iterationsText_ = _1[1];
244
- const saltText_ = _1[2];
245
- const hashText_ = _1[3];
246
- const _guard1 = ff_core_String.String_getInt(iterationsText_);
247
- if(_guard1.Some) {
248
- const iterations_ = _guard1.value_;
249
- const computedHash_ = ff_core_Crypto.internalMakePasswordHash_(ff_core_Buffer.fromHex_(saltText_), ff_core_String.String_toBuffer(password_), iterations_);
241
+ const _1 = ff_core_String.String_split(passwordHash_, 36);
242
+ if(_1.length === 5 && _1[0] === "" && _1[1] === "pbkdf2-sha256") {
243
+ const iterationsText_ = _1[2];
244
+ const saltText_ = _1[3];
245
+ const hashText_ = _1[4];
246
+ const _guard2 = ff_core_String.String_getInt(iterationsText_);
247
+ if(_guard2.Some) {
248
+ const iterations_ = _guard2.value_;
249
+ if(((iterations_ >= minIterations_) && (iterations_ <= maxIterations_))) {
250
+ const computedHash_ = (await ff_core_Crypto.internalHashPassword_$(self_, ff_core_Buffer.fromHex_(saltText_), ff_core_String.String_toBuffer((password_ + pepper_)), iterations_, $task));
250
251
  const hash_ = ff_core_Buffer.fromHex_(hashText_);
251
252
  return (await ff_core_Crypto.Crypto_constantTimeEquals$(self_, computedHash_, hash_, $task))
252
253
  }
253
254
  }
255
+ }
254
256
  {
255
257
  return false
256
258
  }
@@ -264,7 +266,8 @@ return false
264
266
  let v_ = 0;
265
267
  let i_ = 0;
266
268
  while((i_ < ff_core_Buffer.Buffer_size(buffer1_))) {
267
- v_ = ff_core_Int.Int_bitOr(v_, ff_core_Int.Int_bitXor(ff_core_Buffer.Buffer_grabUint8(buffer1_, i_), ff_core_Buffer.Buffer_grabUint8(buffer2_, i_)))
269
+ v_ = ff_core_Int.Int_bitOr(v_, ff_core_Int.Int_bitXor(ff_core_Buffer.Buffer_grabUint8(buffer1_, i_), ff_core_Buffer.Buffer_grabUint8(buffer2_, i_)));
270
+ i_ += 1
268
271
  };
269
272
  return (v_ === 0)
270
273
  }
@@ -94,18 +94,56 @@ import * as ff_core_Unit from "../../ff/core/Unit.mjs"
94
94
 
95
95
 
96
96
 
97
+ export function fromIso_(date_) {
98
+ const zone_ = ((ff_core_String.String_endsWith(date_, "Z") || ff_core_String.String_contains(date_, "+")) || ff_core_String.String_contains(ff_core_String.String_dropWhile(date_, ((_w1) => {
99
+ return (_w1 !== 84)
100
+ })), "-"));
101
+ if((((zone_ && ff_core_String.String_contains(ff_core_String.String_takeWhile(date_, ((_w1) => {
102
+ return (_w1 !== 84)
103
+ })), "-")) && ff_core_String.String_contains(date_, "T")) && ff_core_String.String_contains(date_, ":"))) {
104
+ return ff_core_Option.Some(ff_core_Instant.internalParseDate_(date_))
105
+ } else return ff_core_Option.None()
106
+ }
97
107
 
108
+ export function internalParseDate_(date_) {
98
109
 
110
+ return Date.parse(date_) * 0.001;
111
+
112
+ }
99
113
 
114
+ export async function fromIso_$(date_, $task) {
115
+ const zone_ = ((ff_core_String.String_endsWith(date_, "Z") || ff_core_String.String_contains(date_, "+")) || ff_core_String.String_contains(ff_core_String.String_dropWhile(date_, ((_w1) => {
116
+ return (_w1 !== 84)
117
+ })), "-"));
118
+ if((((zone_ && ff_core_String.String_contains(ff_core_String.String_takeWhile(date_, ((_w1) => {
119
+ return (_w1 !== 84)
120
+ })), "-")) && ff_core_String.String_contains(date_, "T")) && ff_core_String.String_contains(date_, ":"))) {
121
+ return ff_core_Option.Some(ff_core_Instant.internalParseDate_(date_))
122
+ } else return ff_core_Option.None()
123
+ }
124
+
125
+ export async function internalParseDate_$(date_, $task) {
126
+ throw new Error('Function internalParseDate is missing on this target in async context.');
127
+ }
100
128
 
101
129
  export function Instant_add(self_, duration_) {
102
130
  return (self_ + duration_)
103
131
  }
104
132
 
133
+ export function Instant_toIso(self_) {
134
+
135
+ return new Date(self_ * 1000).toISOString();
136
+
137
+ }
138
+
105
139
  export async function Instant_add$(self_, duration_, $task) {
106
140
  return (self_ + duration_)
107
141
  }
108
142
 
143
+ export async function Instant_toIso$(self_, $task) {
144
+ throw new Error('Function Instant_toIso is missing on this target in async context.');
145
+ }
146
+
109
147
 
110
148
 
111
149
 
@@ -1098,7 +1098,7 @@ const builder_ = ff_core_Array.new_();
1098
1098
  ff_core_Stream.Stream_each(self_, ((_w1) => {
1099
1099
  ff_core_Array.Array_push(builder_, _w1)
1100
1100
  }));
1101
- return ff_core_Buffer.fromBufferArray_(ff_core_Array.Array_drain(builder_))
1101
+ return ff_core_Buffer.fromBufferList_(ff_core_Array.Array_drain(builder_))
1102
1102
  }
1103
1103
 
1104
1104
  export function Stream_toString(self_, encoding_ = "utf8") {
@@ -1133,7 +1133,7 @@ const builder_ = ff_core_Array.new_();
1133
1133
  (await ff_core_Stream.Stream_each$(self_, (async (_w1, $task) => {
1134
1134
  ff_core_Array.Array_push(builder_, _w1)
1135
1135
  }), $task));
1136
- return ff_core_Buffer.fromBufferArray_(ff_core_Array.Array_drain(builder_))
1136
+ return ff_core_Buffer.fromBufferList_(ff_core_Array.Array_drain(builder_))
1137
1137
  }
1138
1138
 
1139
1139
  export async function Stream_toString$(self_, encoding_ = "utf8", $task) {
package/package.json CHANGED
@@ -1,29 +1,29 @@
1
1
  {
2
- "name": "firefly-compiler",
3
- "displayName": "Firefly Compiler",
4
- "description": "Firefly compiler",
5
- "author": "Firefly team",
6
- "license": "MIT",
7
- "version": "0.4.36",
8
- "repository": {
9
- "type": "git",
10
- "url": "https://github.com/Ahnfelt/firefly-boot"
11
- },
12
- "publisher": "firefly-team",
13
- "categories": [
14
- "Programming Languages"
15
- ],
16
- "engines": {
17
- "node": ">=18.0.0"
18
- },
19
- "main": "./vscode/client/out/extension",
20
- "icon": "./vscode/icons/firefly-logo.png",
21
- "dependencies": {
22
- "pkg": "^5.8.0",
23
- "tar": "^6.1.11",
24
- "esbuild": "^0.21.3"
25
- },
26
- "bin": {
27
- "firefly": "./bin/firefly.mjs"
28
- }
2
+ "name": "firefly-compiler",
3
+ "displayName": "Firefly Compiler",
4
+ "description": "Firefly compiler",
5
+ "author": "Firefly team",
6
+ "license": "MIT",
7
+ "version": "0.4.40",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Ahnfelt/firefly-boot"
11
+ },
12
+ "publisher": "firefly-team",
13
+ "categories": [
14
+ "Programming Languages"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18.0.0"
18
+ },
19
+ "main": "./vscode/client/out/extension",
20
+ "icon": "./vscode/icons/firefly-logo.png",
21
+ "dependencies": {
22
+ "pkg": "^5.8.0",
23
+ "tar": "^6.1.11",
24
+ "esbuild": "^0.21.3"
25
+ },
26
+ "bin": {
27
+ "firefly": "./bin/firefly.mjs"
28
+ }
29
29
  }
@@ -0,0 +1 @@
1
+ package ff:s3:0.0.0
@@ -10,7 +10,7 @@ put(
10
10
  ): Unit {
11
11
  let now = system.mainTask().now()
12
12
  let amzDate = toIsoString(now)
13
- let contentHash = Digest.sha256(body).toHex()
13
+ let contentHash = system.crypto().sha256(body).toHex()
14
14
  let host = bucket + ".s3.amazonaws.com"
15
15
  let encodedKey = encode(objectKey)
16
16
  let canonicalHeaders = [
@@ -4,7 +4,7 @@
4
4
  "description": "Firefly language support",
5
5
  "author": "Firefly team",
6
6
  "license": "MIT",
7
- "version": "0.4.36",
7
+ "version": "0.4.40",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "https://github.com/Ahnfelt/firefly-boot"
@@ -1,149 +0,0 @@
1
- import Crypto from ff:core
2
-
3
- capability SubtleCrypto(crypto: Crypto)
4
-
5
- data CryptoKey {}
6
-
7
- data CryptoKeyUsages(
8
- encrypt: Bool = False
9
- decrypt: Bool = False
10
- sign: Bool = False
11
- verify: Bool = False
12
- deriveKey: Bool = False
13
- deriveBits: Bool = False
14
- wrapKey: Bool = False
15
- unwrapKey: Bool = False
16
- )
17
-
18
- class CryptoCipher {
19
- RsaOaep(label: Option[String] = None)
20
- AesCtr(counter: Buffer, length: Int)
21
- AesCbc(initializationVector: Buffer)
22
- AesGcm(initializationVector: Buffer, additionalData: Option[Buffer] = None, tagLength: Int = 128)
23
- }
24
-
25
- class CryptoDeriver {
26
- Ecdh(public: CryptoKey)
27
- Hkdf(hash: CryptoDigest, salt: Buffer, info: Buffer)
28
- Pbkdf2(hash: CryptoDigest, salt: Buffer, iterations: Int)
29
- }
30
-
31
- class CryptoGenerator {
32
- HmacGenerator(hash: CryptoDigest, length: Option[Int])
33
- AesCtrGenerator(length: Int)
34
- AesCbcGenerator(length: Int)
35
- AesGcmGenerator(length: Int)
36
- AesKwGenerator(length: Int)
37
- HkdfGenerator(hash: CryptoDigest, salt: Buffer, info: Buffer)
38
- Pbkdf2Generator(hash: CryptoDigest, salt: Buffer, iterations: Int)
39
- }
40
-
41
- class CryptoSigner {
42
- RsassaPkcs1V15
43
- RsaPss(saltLength: Int)
44
- Ecdsa(hash: CryptoDigest)
45
- Hmac
46
- }
47
-
48
- data CryptoDigest {
49
- Sha512
50
- Sha384
51
- Sha256
52
- Sha1
53
- }
54
-
55
- extend self: SubtleCrypto {
56
-
57
- encrypt(algorithm: CryptoCipher, key: CryptoKey, data: Buffer): Buffer
58
- target js async """
59
- const a = internalAlgorithm_(algorithm_);
60
- return new DataView(await self_.encrypt(a, key_, data_));
61
- """
62
-
63
- decrypt(algorithm: CryptoCipher, key: CryptoKey, data: Buffer): Buffer
64
- target js async """
65
- const a = internalAlgorithm_(algorithm_);
66
- return new DataView(await self_.decrypt(a, key_, data_));
67
- """
68
-
69
- sign(algorithm: CryptoSigner, key: CryptoKey, data: Buffer): Buffer
70
- target js async """
71
- const a = internalAlgorithm_(algorithm_);
72
- return new DataView(await self_.sign(a, key_, data_));
73
- """
74
-
75
- verify(algorithm: CryptoSigner, key: CryptoKey, data: Buffer): Bool
76
- target js async """
77
- const a = internalAlgorithm_(algorithm_);
78
- return await self_.verify(a, key_, data_);
79
- """
80
-
81
- digest(algorithm: CryptoDigest, data: Buffer): Buffer
82
- target js async """
83
- const a = internalAlgorithm_(algorithm_);
84
- return new DataView(await self_.digest(a, data_));
85
- """
86
-
87
- deriveBits(algorithm: CryptoDeriver, key: CryptoKey, bits: Int): Buffer
88
- target js async """
89
- const a = internalAlgorithm_(algorithm_);
90
- return new DataView(await self_.deriveBits(a, key_, bits_));
91
- """
92
-
93
- deriveKey(
94
- algorithm: CryptoDeriver
95
- baseKey: CryptoKey
96
- derivedKeyAlgorithm: CryptoGenerator
97
- extractable: Bool
98
- keyUsages: CryptoKeyUsages
99
- ): CryptoKey
100
- target js async """
101
- const a = internalAlgorithm_(algorithm_);
102
- const d = internalAlgorithm_(derivedKeyAlgorithm_);
103
- const u = internalKeyUsages_(keyUsages_);
104
- return await self_.deriveKey(a, baseKey_, d, extractable_, u);
105
- """
106
-
107
- }
108
-
109
- internalAlgorithm(algorithm: JsValue): JsValue
110
- target js sync """
111
- if(algorithm_.Sha512) return 'SHA-512';
112
- if(algorithm_.Sha384) return 'SHA-384';
113
- if(algorithm_.Sha256) return 'SHA-256';
114
- if(algorithm_.Sha1) return 'SHA-1';
115
- if(algorithm_.RsassaPkcs1V15) return 'RSASSA-PKCS1-v1_5';
116
- if(algorithm_.RsaPss) return {name: 'RSA-PSS', saltLength: algorithm_.saltLength_};
117
- if(algorithm_.Ecdsa) return {name: 'ECDSA', hash: internalAlgorithm_(algorithm_.hash_)};
118
- if(algorithm_.Hmac) return 'HMAC';
119
- if(algorithm_.Ecdh) return {name: 'ECDH', public: algorithm_.public_};
120
- if(algorithm_.Hkdf) return {name: 'HKDF', hash: internalAlgorithm_(algorithm_.hash_), salt: algorithm_.salt_, info: algorithm_.info_};
121
- if(algorithm_.Pbkdf2) return {name: 'PBKDF2', hash: internalAlgorithm_(algorithm_.hash_), salt: algorithm_.salt_, iterations: algorithm_.iterations_};
122
- if(algorithm_.RsaOaep) return {name: "RSA-OAEP", label: algorithm_.label_.value_};
123
- if(algorithm_.AesCtr) return {name: "AES-CTR", counter: algorithm_.counter_, length: algorithm_.length_};
124
- if(algorithm_.AesCbc) return {name: "AES-CBC", iv: algorithm_.initializationVector_};
125
- if(algorithm_.AesGcm) return {name: "AES-GCM", iv: algorithm_.initializationVector_, additionalData: algorithm_.value_, tagLength: algorithm_.tagLength_};
126
- // Turns out, generateKey has different parameters - think about naming
127
- if(algorithm_.HmacGenerator) return {name: 'HMAC', hash: internalAlgorithm_(algorithm_.hash_), length: algorithm_.length_.value_};
128
- if(algorithm_.AesCtrGenerator) return {name: 'AES-CTR', length: algorithm_.length_};
129
- if(algorithm_.AesCbcGenerator) return {name: 'AES-CBC', length: algorithm_.length_};
130
- if(algorithm_.AesGcmGenerator) return {name: 'AES-GCM', length: algorithm_.length_};
131
- if(algorithm_.AesKwGenerator) return {name: 'AES-KW', length: algorithm_.length_};
132
- if(algorithm_.HkdfGenerator) return {name: 'HKDF', hash: internalAlgorithm_(algorithm_.hash_), salt: algorithm_.salt_, info: algorithm_.info_};
133
- if(algorithm_.Pbkdf2Generator) return {name: 'PBKDF2', hash: internalAlgorithm_(algorithm_.hash_), salt: algorithm_.salt_, iterations: algorithm_.iterations_};
134
- throw new Error('No such algorithm');
135
- """
136
-
137
- internalKeyUsages(keyUsages: JsValue): JsValue
138
- target js sync """
139
- const u = [];
140
- if(keyUsages_.encrypt_) u.push('encrypt');
141
- if(keyUsages_.decrypt_) u.push('decrypt');
142
- if(keyUsages_.sign_) u.push('sign');
143
- if(keyUsages_.verify_) u.push('verify');
144
- if(keyUsages_.deriveKey_) u.push('deriveKey');
145
- if(keyUsages_.deriveBits_) u.push('deriveBits');
146
- if(keyUsages_.wrapKey_) u.push('wrapKey');
147
- if(keyUsages_.unwrapKey_) u.push('unwrapKey');
148
- return u;
149
- """