firefly-compiler 0.4.34 → 0.4.36
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 +47 -4
- package/compiler/Compiler.ff +1 -0
- package/core/Crypto.ff +95 -0
- package/core/NodeSystem.ff +4 -1
- package/core/Pair.ff +9 -0
- package/crypto/SubtleCrypto.ff +149 -0
- package/experimental/s3/S3.ff +93 -0
- package/experimental/s3/S3TestAuthorizationHeader.ff +39 -0
- package/experimental/s3/S3TestPut.ff +16 -0
- package/output/js/ff/compiler/Builder.mjs +2 -0
- package/output/js/ff/compiler/Compiler.mjs +3 -1
- package/output/js/ff/compiler/Dependencies.mjs +2 -0
- package/output/js/ff/compiler/DependencyLock.mjs +2 -0
- package/output/js/ff/compiler/Deriver.mjs +2 -0
- package/output/js/ff/compiler/Dictionaries.mjs +2 -0
- package/output/js/ff/compiler/Environment.mjs +2 -0
- package/output/js/ff/compiler/Inference.mjs +2 -0
- package/output/js/ff/compiler/JsEmitter.mjs +2 -0
- package/output/js/ff/compiler/JsImporter.mjs +2 -0
- package/output/js/ff/compiler/LspHook.mjs +2 -0
- package/output/js/ff/compiler/Main.mjs +2 -0
- package/output/js/ff/compiler/ModuleCache.mjs +2 -0
- package/output/js/ff/compiler/Parser.mjs +2 -0
- package/output/js/ff/compiler/Patterns.mjs +2 -0
- package/output/js/ff/compiler/Resolver.mjs +2 -0
- package/output/js/ff/compiler/Substitution.mjs +2 -0
- package/output/js/ff/compiler/Syntax.mjs +2 -0
- package/output/js/ff/compiler/Token.mjs +2 -0
- package/output/js/ff/compiler/Tokenizer.mjs +2 -0
- package/output/js/ff/compiler/Unification.mjs +2 -0
- package/output/js/ff/compiler/Wildcards.mjs +2 -0
- package/output/js/ff/compiler/Workspace.mjs +2 -0
- package/output/js/ff/core/Any.mjs +2 -0
- package/output/js/ff/core/Array.mjs +2 -0
- package/output/js/ff/core/AssetSystem.mjs +2 -0
- package/output/js/ff/core/Atomic.mjs +2 -0
- package/output/js/ff/core/Bool.mjs +2 -0
- package/output/js/ff/core/BrowserSystem.mjs +2 -0
- package/output/js/ff/core/Buffer.mjs +2 -0
- package/output/js/ff/core/BuildSystem.mjs +2 -0
- package/output/js/ff/core/Channel.mjs +2 -0
- package/output/js/ff/core/Char.mjs +2 -0
- package/output/js/ff/core/Core.mjs +2 -0
- package/output/js/ff/core/Crypto.mjs +275 -0
- package/output/js/ff/core/Duration.mjs +2 -0
- package/output/js/ff/core/Equal.mjs +2 -0
- package/output/js/ff/core/Error.mjs +2 -0
- package/output/js/ff/core/FileHandle.mjs +2 -0
- package/output/js/ff/core/Float.mjs +2 -0
- package/output/js/ff/core/HttpClient.mjs +2 -0
- package/output/js/ff/core/Instant.mjs +2 -0
- package/output/js/ff/core/Int.mjs +2 -0
- package/output/js/ff/core/IntMap.mjs +2 -0
- package/output/js/ff/core/JsSystem.mjs +2 -0
- package/output/js/ff/core/JsValue.mjs +2 -0
- package/output/js/ff/core/Json.mjs +2 -0
- package/output/js/ff/core/List.mjs +2 -0
- package/output/js/ff/core/Lock.mjs +2 -0
- package/output/js/ff/core/Log.mjs +2 -0
- package/output/js/ff/core/Map.mjs +2 -0
- package/output/js/ff/core/NodeSystem.mjs +11 -1
- package/output/js/ff/core/Nothing.mjs +2 -0
- package/output/js/ff/core/Option.mjs +2 -0
- package/output/js/ff/core/Ordering.mjs +2 -0
- package/output/js/ff/core/Pair.mjs +10 -0
- package/output/js/ff/core/Path.mjs +2 -0
- package/output/js/ff/core/Random.mjs +2 -0
- package/output/js/ff/core/RbMap.mjs +2 -0
- package/output/js/ff/core/Serializable.mjs +2 -0
- package/output/js/ff/core/Set.mjs +2 -0
- package/output/js/ff/core/Show.mjs +2 -0
- package/output/js/ff/core/SourceLocation.mjs +2 -0
- package/output/js/ff/core/Stream.mjs +2 -0
- package/output/js/ff/core/String.mjs +2 -0
- package/output/js/ff/core/StringMap.mjs +2 -0
- package/output/js/ff/core/Task.mjs +2 -0
- package/output/js/ff/core/Try.mjs +2 -0
- package/output/js/ff/core/Unit.mjs +2 -0
- package/package.json +1 -1
- package/vscode/package.json +1 -1
package/bin/Release.ff
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
nodeMain(system: NodeSystem) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
run(system: NodeSystem, command: String, arguments: List[String], workingDirectory: Path) {
|
|
13
|
+
system.writeLine("")
|
|
14
|
+
system.writeLine(command + " " + arguments.join(" "))
|
|
15
|
+
let out = system.execute(command, arguments, workingDirectory = Some(workingDirectory))
|
|
16
|
+
system.writeBuffer(out.standardOut)
|
|
17
|
+
system.writeErrorBuffer(out.standardError)
|
|
18
|
+
if(out.exitCode != 0) {
|
|
19
|
+
system.writeErrorLine("Exit code: " + out.exitCode)
|
|
20
|
+
system.exit(1)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
bumpMinorVersion(system: NodeSystem, packageJsonPath: Path) {
|
|
25
|
+
let prefix = " \"version\": \""
|
|
26
|
+
mutable bumps = 0
|
|
27
|
+
system.writeLine("")
|
|
28
|
+
system.writeLine("Bumping version in " + packageJsonPath.absolute())
|
|
29
|
+
let newContent = packageJsonPath.readText().lines().map {
|
|
30
|
+
| line {
|
|
31
|
+
line.removeFirst(prefix).flatMap {_.removeLast("\",")} | Some(v)
|
|
32
|
+
} {
|
|
33
|
+
v.split('.') | [major, minor, patch]
|
|
34
|
+
} {
|
|
35
|
+
patch.getInt() | Some(p)
|
|
36
|
+
} =>
|
|
37
|
+
bumps += 1
|
|
38
|
+
let newVersion = major + "." + minor + "." + (p + 1)
|
|
39
|
+
system.writeLine("Will bump version: " + v + " to " + newVersion)
|
|
40
|
+
prefix + newVersion + "\","
|
|
41
|
+
| line =>
|
|
42
|
+
line
|
|
43
|
+
}.join("\n")
|
|
44
|
+
if(bumps != 1) {
|
|
45
|
+
system.writeErrorLine("Failed to bump version.")
|
|
46
|
+
system.exit(1)
|
|
47
|
+
}
|
|
48
|
+
packageJsonPath.writeText(newContent)
|
|
6
49
|
}
|
package/compiler/Compiler.ff
CHANGED
package/core/Crypto.ff
ADDED
|
@@ -0,0 +1,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
|
+
makePasswordHash(password: String, iterations: Int = 100000): String {
|
|
45
|
+
let salt = self.randomBuffer(16)
|
|
46
|
+
let hash = internalMakePasswordHash(salt, password.toBuffer(), iterations)
|
|
47
|
+
"PSG_" + iterations + "_" + salt.toHex() + "_" + hash.toHex()
|
|
48
|
+
}
|
|
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)
|
|
54
|
+
let hash = Buffer.fromHex(hashText)
|
|
55
|
+
self.constantTimeEquals(computedHash, hash)
|
|
56
|
+
| _ => False
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
constantTimeEquals(buffer1: Buffer, buffer2: Buffer): Bool {
|
|
61
|
+
if(buffer1.size() != buffer2.size()) {False} else:
|
|
62
|
+
mutable v = 0
|
|
63
|
+
mutable i = 0
|
|
64
|
+
while {i < buffer1.size()} {
|
|
65
|
+
v = v.bitOr(buffer1.grabUint8(i).bitXor(buffer2.grabUint8(i)))
|
|
66
|
+
}
|
|
67
|
+
v == 0
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
internalMakePasswordHash(salt: Buffer, password: Buffer, iterations: Int): Buffer
|
|
73
|
+
target js async """
|
|
74
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
75
|
+
'raw',
|
|
76
|
+
password_,
|
|
77
|
+
{name: 'PBKDF2'},
|
|
78
|
+
false,
|
|
79
|
+
['deriveKey']
|
|
80
|
+
);
|
|
81
|
+
const derivedKey = await crypto.subtle.deriveKey(
|
|
82
|
+
{
|
|
83
|
+
name: 'PBKDF2',
|
|
84
|
+
salt: salt_,
|
|
85
|
+
iterations: iterations_,
|
|
86
|
+
hash: 'SHA-256'
|
|
87
|
+
},
|
|
88
|
+
keyMaterial,
|
|
89
|
+
{name: 'AES-GCM', length: 256},
|
|
90
|
+
true,
|
|
91
|
+
['encrypt', 'decrypt']
|
|
92
|
+
);
|
|
93
|
+
const hashBuffer = await crypto.subtle.exportKey('raw', derivedKey);
|
|
94
|
+
return new DataView(hashBuffer);
|
|
95
|
+
"""
|
package/core/NodeSystem.ff
CHANGED
|
@@ -45,6 +45,9 @@ extend self: NodeSystem {
|
|
|
45
45
|
mainTask(): Task
|
|
46
46
|
target js async "return self_.task_"
|
|
47
47
|
|
|
48
|
+
crypto()
|
|
49
|
+
target js async "return (typeof globalThis !== 'undefined' ? globalThis : window).crypto"
|
|
50
|
+
|
|
48
51
|
js(): JsSystem
|
|
49
52
|
target js async "return typeof globalThis !== 'undefined' ? globalThis : window"
|
|
50
53
|
|
|
@@ -156,7 +159,7 @@ extend self: NodeSystem {
|
|
|
156
159
|
const o = Buffer.concat(out);
|
|
157
160
|
const e = Buffer.concat(err);
|
|
158
161
|
resolve(ProcessResult(
|
|
159
|
-
|
|
162
|
+
code,
|
|
160
163
|
new DataView(o.buffer, o.byteOffset, o.byteLength),
|
|
161
164
|
new DataView(e.buffer, e.byteOffset, e.byteLength),
|
|
162
165
|
));
|
package/core/Pair.ff
CHANGED
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
"""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
put(
|
|
2
|
+
system: NodeSystem
|
|
3
|
+
accessKeyId: String
|
|
4
|
+
secretAccessKey: String
|
|
5
|
+
region: String
|
|
6
|
+
bucket: String
|
|
7
|
+
objectKey: String
|
|
8
|
+
body: Buffer
|
|
9
|
+
headers: List[Pair[String, String]]
|
|
10
|
+
): Unit {
|
|
11
|
+
let now = system.mainTask().now()
|
|
12
|
+
let amzDate = toIsoString(now)
|
|
13
|
+
let contentHash = Digest.sha256(body).toHex()
|
|
14
|
+
let host = bucket + ".s3.amazonaws.com"
|
|
15
|
+
let encodedKey = encode(objectKey)
|
|
16
|
+
let canonicalHeaders = [
|
|
17
|
+
Pair("host", host)
|
|
18
|
+
Pair("x-amz-date", amzDate)
|
|
19
|
+
Pair("x-amz-content-sha256", contentHash)
|
|
20
|
+
...headers
|
|
21
|
+
]
|
|
22
|
+
let authenticationHeader = makeS3AuthorizationHeader(system, accessKeyId, secretAccessKey, region, bucket, encodedKey, body, canonicalHeaders, amzDate)
|
|
23
|
+
let allHeaders = [...canonicalHeaders, Pair("Authorization", authenticationHeader)]
|
|
24
|
+
|
|
25
|
+
let url = "https://" + host + "/" + encodedKey
|
|
26
|
+
let response = system.httpClient().fetch(url, method = "PUT", headers = allHeaders, body = Some(HttpClient.bodyBuffer(body)), throw = False)
|
|
27
|
+
system.writeLine("" + response.status())
|
|
28
|
+
system.writeLine(response.statusText())
|
|
29
|
+
system.writeLine(response.readText())
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
makeS3AuthorizationHeader(
|
|
33
|
+
system: NodeSystem
|
|
34
|
+
accessKeyId: String
|
|
35
|
+
secretAccessKey: String
|
|
36
|
+
region: String
|
|
37
|
+
bucket: String
|
|
38
|
+
encodedKey: String
|
|
39
|
+
body: Buffer
|
|
40
|
+
canonicalHeaders: List[Pair[String, String]]
|
|
41
|
+
amzDate: String
|
|
42
|
+
): String {
|
|
43
|
+
// CanonicalRequest
|
|
44
|
+
let canonicalQuerystring = "";
|
|
45
|
+
let contentHash = system.crypto().sha256(body).toHex()
|
|
46
|
+
let headers = canonicalHeaders.map {_.mapFirst {_.lower()}.mapSecond {_.trim()}}.sort()
|
|
47
|
+
let signedHeaders = headers.map {_.first}.join(";")
|
|
48
|
+
let canonicalRequest = [
|
|
49
|
+
"PUT"
|
|
50
|
+
"/" + encodedKey
|
|
51
|
+
canonicalQuerystring
|
|
52
|
+
...headers.map {p => p.first + ":" + p.second}
|
|
53
|
+
""
|
|
54
|
+
signedHeaders
|
|
55
|
+
contentHash
|
|
56
|
+
].join("\n")
|
|
57
|
+
|
|
58
|
+
// StringToSign
|
|
59
|
+
let scopeDate = amzDate.slice(0, 8) // YYYYMMDD
|
|
60
|
+
let credentialScope = [scopeDate, region, "s3", "aws4_request"].join("/")
|
|
61
|
+
let algorithm = "AWS4-HMAC-SHA256"
|
|
62
|
+
let stringToSign = [
|
|
63
|
+
algorithm
|
|
64
|
+
amzDate
|
|
65
|
+
credentialScope
|
|
66
|
+
system.crypto().sha256(canonicalRequest.toBuffer()).toHex()
|
|
67
|
+
].join("\n")
|
|
68
|
+
|
|
69
|
+
function hmacSha256(key: Buffer, message: String): Buffer {
|
|
70
|
+
system.crypto().hmacSha256(key, message.toBuffer())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Signature
|
|
74
|
+
let signingKey = hmacSha256(hmacSha256(hmacSha256(hmacSha256(("AWS4" + secretAccessKey).toBuffer(), scopeDate), region), "s3"), "aws4_request")
|
|
75
|
+
let signature = hmacSha256(signingKey, stringToSign).toHex()
|
|
76
|
+
|
|
77
|
+
algorithm + " Credential=" + accessKeyId + "/" + credentialScope + ",SignedHeaders=" + signedHeaders + ",Signature=" + signature
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
toIsoString(instant: Instant): String
|
|
81
|
+
target js sync """
|
|
82
|
+
const d = new Date(instant_ * 1000);
|
|
83
|
+
return d.toISOString().replaceAll(/[-:]|[.].../g, "");
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
encodeURIComponent(text: String): String
|
|
87
|
+
target js sync """
|
|
88
|
+
return encodeURIComponent(text_);
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
encode(text: String): String {
|
|
92
|
+
text.split('/').map {encodeURIComponent(_)}.join("/")
|
|
93
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import S3
|
|
2
|
+
|
|
3
|
+
nodeMain(system: NodeSystem) {
|
|
4
|
+
// Trying to reproduce the result from an example here
|
|
5
|
+
// https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
|
|
6
|
+
let expectedHeader = "AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=date;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class,Signature=98ad721746da40c64f1a55b78f14c238d841ea1380cd77a1b5971af0ece108bd"
|
|
7
|
+
let amzDate = "20130524T000000Z" // TODO
|
|
8
|
+
let headerDate = "Fri, 24 May 2013 00:00:00 GMT" // TODO
|
|
9
|
+
let bucket = "examplebucket"
|
|
10
|
+
let body = "Welcome to Amazon S3.".toBuffer()
|
|
11
|
+
let actualHeader = S3.makeS3AuthorizationHeader(
|
|
12
|
+
system = system
|
|
13
|
+
accessKeyId = "AKIAIOSFODNN7EXAMPLE"
|
|
14
|
+
secretAccessKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
|
15
|
+
region = "us-east-1"
|
|
16
|
+
bucket = bucket
|
|
17
|
+
encodedKey = S3.encode("test$file.text")
|
|
18
|
+
body = body
|
|
19
|
+
canonicalHeaders = [
|
|
20
|
+
Pair("date", headerDate)
|
|
21
|
+
Pair("host", bucket + ".s3.amazonaws.com")
|
|
22
|
+
Pair("x-amz-date", amzDate)
|
|
23
|
+
Pair("x-amz-content-sha256", system.crypto().sha256(body).toHex())
|
|
24
|
+
Pair("x-amz-storage-class", "REDUCED_REDUNDANCY")
|
|
25
|
+
]
|
|
26
|
+
amzDate = amzDate
|
|
27
|
+
)
|
|
28
|
+
system.writeLine("")
|
|
29
|
+
system.writeLine("actual : " + actualHeader)
|
|
30
|
+
system.writeLine("")
|
|
31
|
+
system.writeLine("expected: " + expectedHeader)
|
|
32
|
+
|
|
33
|
+
system.writeLine("")
|
|
34
|
+
if(actualHeader == expectedHeader) {
|
|
35
|
+
system.writeLine("Test passed")
|
|
36
|
+
} else {
|
|
37
|
+
system.writeLine("Test failed")
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import S3
|
|
2
|
+
|
|
3
|
+
nodeMain(system: NodeSystem) {
|
|
4
|
+
S3.put(system,
|
|
5
|
+
accessKeyId = ""
|
|
6
|
+
secretAccessKey = ""
|
|
7
|
+
region = "eu-central-1"
|
|
8
|
+
bucket = "firefly-site"
|
|
9
|
+
objectKey = "tmp/test4"
|
|
10
|
+
"Hello S3 3".toBuffer()
|
|
11
|
+
headers = [
|
|
12
|
+
//Pair("x-amz-storage-class", "REDUCED_REDUNDANCY")
|
|
13
|
+
Pair("Content-Type", "text/plain")
|
|
14
|
+
]
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -46,6 +46,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
46
46
|
|
|
47
47
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
48
48
|
|
|
49
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
50
|
+
|
|
49
51
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
50
52
|
|
|
51
53
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -46,6 +46,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
46
46
|
|
|
47
47
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
48
48
|
|
|
49
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
50
|
+
|
|
49
51
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
50
52
|
|
|
51
53
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -117,7 +119,7 @@ export function Compiler(emitTarget_, task_, compilerModulePath_, jsOutputPath_,
|
|
|
117
119
|
return {emitTarget_, task_, compilerModulePath_, jsOutputPath_, packagePaths_, singleFilePackages_, virtualFiles_, cache_, lspHook_, phaseDurationDelta_, phaseDurations_};
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
export const coreImports_ = ff_core_List.List_map(["Any", "Array", "AssetSystem", "Atomic", "Bool", "BrowserSystem", "Buffer", "BuildSystem", "Channel", "Char", "Core", "Duration", "Equal", "Error", "FileHandle", "Float", "HttpClient", "Instant", "Int", "IntMap", "Json", "JsValue", "JsSystem", "List", "Lock", "Log", "Map", "NodeSystem", "Nothing", "Option", "Ordering", "Pair", "Path", "Random", "Serializable", "Set", "Show", "SourceLocation", "Stream", "String", "StringMap", "Task", "Try", "Unit"], ((moduleName_) => {
|
|
122
|
+
export const coreImports_ = ff_core_List.List_map(["Any", "Array", "AssetSystem", "Atomic", "Bool", "BrowserSystem", "Buffer", "BuildSystem", "Channel", "Char", "Core", "Crypto", "Duration", "Equal", "Error", "FileHandle", "Float", "HttpClient", "Instant", "Int", "IntMap", "Json", "JsValue", "JsSystem", "List", "Lock", "Log", "Map", "NodeSystem", "Nothing", "Option", "Ordering", "Pair", "Path", "Random", "Serializable", "Set", "Show", "SourceLocation", "Stream", "String", "StringMap", "Task", "Try", "Unit"], ((moduleName_) => {
|
|
121
123
|
return ff_compiler_Syntax.DImport(ff_compiler_Syntax.Location("<prelude>", 1, 1), moduleName_, ff_compiler_Syntax.PackagePair("ff", "core"), [], moduleName_)
|
|
122
124
|
}));
|
|
123
125
|
|
|
@@ -36,6 +36,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
36
36
|
|
|
37
37
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
38
38
|
|
|
39
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
40
|
+
|
|
39
41
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
40
42
|
|
|
41
43
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -24,6 +24,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
24
24
|
|
|
25
25
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
26
26
|
|
|
27
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
28
|
+
|
|
27
29
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
28
30
|
|
|
29
31
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -26,6 +26,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
26
26
|
|
|
27
27
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
28
28
|
|
|
29
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
30
|
+
|
|
29
31
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
30
32
|
|
|
31
33
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -30,6 +30,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
30
30
|
|
|
31
31
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
32
32
|
|
|
33
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
34
|
+
|
|
33
35
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
34
36
|
|
|
35
37
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -26,6 +26,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
26
26
|
|
|
27
27
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
28
28
|
|
|
29
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
30
|
+
|
|
29
31
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
30
32
|
|
|
31
33
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -34,6 +34,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
34
34
|
|
|
35
35
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
36
36
|
|
|
37
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
38
|
+
|
|
37
39
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
38
40
|
|
|
39
41
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -30,6 +30,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
30
30
|
|
|
31
31
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
32
32
|
|
|
33
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
34
|
+
|
|
33
35
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
34
36
|
|
|
35
37
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -26,6 +26,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
26
26
|
|
|
27
27
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
28
28
|
|
|
29
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
30
|
+
|
|
29
31
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
30
32
|
|
|
31
33
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -30,6 +30,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
30
30
|
|
|
31
31
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
32
32
|
|
|
33
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
34
|
+
|
|
33
35
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
34
36
|
|
|
35
37
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -50,6 +50,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
50
50
|
|
|
51
51
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
52
52
|
|
|
53
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
54
|
+
|
|
53
55
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
54
56
|
|
|
55
57
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -26,6 +26,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
26
26
|
|
|
27
27
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
28
28
|
|
|
29
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
30
|
+
|
|
29
31
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
30
32
|
|
|
31
33
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -32,6 +32,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
32
32
|
|
|
33
33
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
34
34
|
|
|
35
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
36
|
+
|
|
35
37
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
36
38
|
|
|
37
39
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|
|
@@ -26,6 +26,8 @@ import * as ff_core_Char from "../../ff/core/Char.mjs"
|
|
|
26
26
|
|
|
27
27
|
import * as ff_core_Core from "../../ff/core/Core.mjs"
|
|
28
28
|
|
|
29
|
+
import * as ff_core_Crypto from "../../ff/core/Crypto.mjs"
|
|
30
|
+
|
|
29
31
|
import * as ff_core_Duration from "../../ff/core/Duration.mjs"
|
|
30
32
|
|
|
31
33
|
import * as ff_core_Equal from "../../ff/core/Equal.mjs"
|