goscript 0.2.1 → 0.2.3
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/compiler/gotest/runner.go +98 -0
- package/compiler/gotest/runner_test.go +45 -0
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +227 -11
- package/compiler/override-registry_test.go +50 -0
- package/compiler/protobuf-ts-binding.go +155 -7
- package/compiler/protobuf-ts-binding_test.go +116 -2
- package/compiler/runtime-contract.go +2 -0
- package/compiler/runtime-contract_test.go +1 -0
- package/compiler/semantic-model.go +16 -0
- package/compiler/semantic-model_test.go +38 -0
- package/compiler/skeleton_test.go +477 -16
- package/compiler/typescript-emitter.go +4 -0
- package/dist/gs/builtin/builtin.js +7 -9
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/defer.js +2 -2
- package/dist/gs/builtin/hostio.js +5 -5
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +2 -1
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +3 -0
- package/dist/gs/builtin/slice.js +39 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +49 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/compress/zlib/index.js +5 -2
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/aes/index.d.ts +15 -0
- package/dist/gs/crypto/aes/index.js +57 -0
- package/dist/gs/crypto/aes/index.js.map +1 -0
- package/dist/gs/crypto/cipher/index.d.ts +41 -0
- package/dist/gs/crypto/cipher/index.js +255 -0
- package/dist/gs/crypto/cipher/index.js.map +1 -0
- package/dist/gs/crypto/ecdh/index.js +27 -8
- package/dist/gs/crypto/ecdh/index.js.map +1 -1
- package/dist/gs/crypto/ed25519/index.js +3 -3
- package/dist/gs/crypto/ed25519/index.js.map +1 -1
- package/dist/gs/crypto/rand/index.js +6 -3
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/embed/index.js +9 -3
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.d.ts +31 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
- package/dist/gs/hash/fnv/index.js +13 -5
- package/dist/gs/hash/fnv/index.js.map +1 -1
- package/dist/gs/io/fs/glob.d.ts +3 -3
- package/dist/gs/io/fs/glob.js +8 -8
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/io/fs/readdir.d.ts +2 -2
- package/dist/gs/io/fs/readdir.js +13 -74
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/sub.js +4 -4
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.js +18 -2
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/mime/index.js +5 -2
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +6 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +16 -4
- package/dist/gs/net/http/index.js +236 -40
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +1 -1
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -0
- package/dist/gs/reflect/type.js +53 -21
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/runtime/debug/index.js +2 -1
- package/dist/gs/runtime/debug/index.js.map +1 -1
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +2 -2
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +1 -1
- package/dist/gs/slices/slices.js +37 -4
- package/dist/gs/slices/slices.js.map +1 -1
- package/go.mod +2 -2
- package/go.sum +2 -0
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.test.ts +8 -3
- package/gs/builtin/hostio.ts +5 -7
- package/gs/builtin/map.ts +4 -1
- package/gs/builtin/slice.test.ts +14 -0
- package/gs/builtin/slice.ts +64 -0
- package/gs/builtin/type.ts +72 -0
- package/gs/bytes/bytes.test.ts +14 -13
- package/gs/compress/zlib/index.test.ts +19 -5
- package/gs/compress/zlib/index.ts +16 -7
- package/gs/context/context.test.ts +3 -1
- package/gs/crypto/aes/index.test.ts +120 -0
- package/gs/crypto/aes/index.ts +76 -0
- package/gs/crypto/cipher/index.ts +345 -0
- package/gs/crypto/cipher/meta.json +6 -0
- package/gs/crypto/ecdh/index.test.ts +6 -2
- package/gs/crypto/ecdh/index.ts +49 -12
- package/gs/crypto/ed25519/index.ts +20 -7
- package/gs/crypto/rand/index.ts +6 -3
- package/gs/embed/index.test.ts +3 -3
- package/gs/embed/index.ts +9 -3
- package/gs/fmt/fmt.test.ts +29 -4
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
- package/gs/golang.org/x/crypto/chacha20poly1305/index.test.ts +91 -0
- package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
- package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
- package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
- package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
- package/gs/hash/fnv/index.test.ts +1 -8
- package/gs/hash/fnv/index.ts +27 -10
- package/gs/io/fs/glob.ts +13 -10
- package/gs/io/fs/meta.json +2 -0
- package/gs/io/fs/readdir.test.ts +63 -2
- package/gs/io/fs/readdir.ts +33 -30
- package/gs/io/fs/sub.ts +4 -4
- package/gs/io/fs/walk.ts +1 -1
- package/gs/io/io.test.ts +56 -1
- package/gs/io/io.ts +19 -2
- package/gs/maps/iter.ts +9 -9
- package/gs/maps/maps.ts +4 -4
- package/gs/math/bits/index.test.ts +10 -1
- package/gs/mime/index.test.ts +33 -15
- package/gs/mime/index.ts +9 -2
- package/gs/net/http/httptest/index.test.ts +17 -3
- package/gs/net/http/httptest/index.ts +8 -3
- package/gs/net/http/index.test.ts +645 -123
- package/gs/net/http/index.ts +548 -113
- package/gs/net/http/pprof/index.ts +24 -6
- package/gs/os/file_unix_js.test.ts +22 -0
- package/gs/reflect/iter.ts +4 -2
- package/gs/reflect/map.test.ts +56 -1
- package/gs/reflect/type.ts +76 -37
- package/gs/runtime/debug/index.test.ts +32 -4
- package/gs/runtime/debug/index.ts +5 -2
- package/gs/runtime/pprof/index.test.ts +7 -1
- package/gs/runtime/pprof/index.ts +5 -1
- package/gs/runtime/runtime.test.ts +7 -0
- package/gs/runtime/runtime.ts +2 -4
- package/gs/runtime/trace/index.test.ts +9 -1
- package/gs/runtime/trace/index.ts +5 -1
- package/gs/slices/meta.json +3 -0
- package/gs/slices/slices.test.ts +59 -21
- package/gs/slices/slices.ts +61 -20
- package/gs/strconv/complex.test.ts +17 -3
- package/gs/sync/atomic/doc_64.test.ts +2 -9
- package/gs/sync/sync.test.ts +18 -8
- package/gs/syscall/js/index.test.ts +9 -4
- package/package.json +13 -5
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
2
|
+
import * as errors from '@goscript/errors/index.js'
|
|
3
|
+
import {
|
|
4
|
+
chacha20poly1305 as nobleChaCha20Poly1305,
|
|
5
|
+
xchacha20poly1305 as nobleXChaCha20Poly1305,
|
|
6
|
+
} from '@noble/ciphers/chacha.js'
|
|
7
|
+
|
|
8
|
+
export const KeySize = 32
|
|
9
|
+
export const NonceSize = 12
|
|
10
|
+
export const NonceSizeX = 24
|
|
11
|
+
export const Overhead = 16
|
|
12
|
+
|
|
13
|
+
const maxIETFPlaintext = 2 ** 38 - 64
|
|
14
|
+
const maxIETFCiphertext = 2 ** 38 - 48
|
|
15
|
+
|
|
16
|
+
type NobleAEAD = typeof nobleChaCha20Poly1305 | typeof nobleXChaCha20Poly1305
|
|
17
|
+
|
|
18
|
+
export let errOpen: $.GoError = errors.New(
|
|
19
|
+
'chacha20poly1305: message authentication failed',
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
export function __goscript_set_errOpen(value: $.GoError): void {
|
|
23
|
+
errOpen = value
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AEAD {
|
|
27
|
+
NonceSize(): number
|
|
28
|
+
Overhead(): number
|
|
29
|
+
Seal(
|
|
30
|
+
dst: $.Slice<number>,
|
|
31
|
+
nonce: $.Slice<number>,
|
|
32
|
+
plaintext: $.Slice<number>,
|
|
33
|
+
additionalData: $.Slice<number>,
|
|
34
|
+
): $.Slice<number>
|
|
35
|
+
Open(
|
|
36
|
+
dst: $.Slice<number>,
|
|
37
|
+
nonce: $.Slice<number>,
|
|
38
|
+
ciphertext: $.Slice<number>,
|
|
39
|
+
additionalData: $.Slice<number>,
|
|
40
|
+
): [$.Slice<number>, $.GoError]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class chacha20poly1305 implements AEAD {
|
|
44
|
+
readonly key: Uint8Array
|
|
45
|
+
|
|
46
|
+
constructor(key: Uint8Array) {
|
|
47
|
+
this.key = key.slice()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
NonceSize(): number {
|
|
51
|
+
return NonceSize
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Overhead(): number {
|
|
55
|
+
return Overhead
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Seal(
|
|
59
|
+
dst: $.Slice<number>,
|
|
60
|
+
nonce: $.Slice<number>,
|
|
61
|
+
plaintext: $.Slice<number>,
|
|
62
|
+
additionalData: $.Slice<number>,
|
|
63
|
+
): $.Slice<number> {
|
|
64
|
+
return seal(
|
|
65
|
+
dst,
|
|
66
|
+
nobleChaCha20Poly1305,
|
|
67
|
+
this.key,
|
|
68
|
+
nonce,
|
|
69
|
+
NonceSize,
|
|
70
|
+
plaintext,
|
|
71
|
+
additionalData,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Open(
|
|
76
|
+
dst: $.Slice<number>,
|
|
77
|
+
nonce: $.Slice<number>,
|
|
78
|
+
ciphertext: $.Slice<number>,
|
|
79
|
+
additionalData: $.Slice<number>,
|
|
80
|
+
): [$.Slice<number>, $.GoError] {
|
|
81
|
+
return open(
|
|
82
|
+
dst,
|
|
83
|
+
nobleChaCha20Poly1305,
|
|
84
|
+
this.key,
|
|
85
|
+
nonce,
|
|
86
|
+
NonceSize,
|
|
87
|
+
ciphertext,
|
|
88
|
+
additionalData,
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class xchacha20poly1305 implements AEAD {
|
|
94
|
+
readonly key: Uint8Array
|
|
95
|
+
|
|
96
|
+
constructor(key: Uint8Array) {
|
|
97
|
+
this.key = key.slice()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
NonceSize(): number {
|
|
101
|
+
return NonceSizeX
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
Overhead(): number {
|
|
105
|
+
return Overhead
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Seal(
|
|
109
|
+
dst: $.Slice<number>,
|
|
110
|
+
nonce: $.Slice<number>,
|
|
111
|
+
plaintext: $.Slice<number>,
|
|
112
|
+
additionalData: $.Slice<number>,
|
|
113
|
+
): $.Slice<number> {
|
|
114
|
+
return seal(
|
|
115
|
+
dst,
|
|
116
|
+
nobleXChaCha20Poly1305,
|
|
117
|
+
this.key,
|
|
118
|
+
nonce,
|
|
119
|
+
NonceSizeX,
|
|
120
|
+
plaintext,
|
|
121
|
+
additionalData,
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
Open(
|
|
126
|
+
dst: $.Slice<number>,
|
|
127
|
+
nonce: $.Slice<number>,
|
|
128
|
+
ciphertext: $.Slice<number>,
|
|
129
|
+
additionalData: $.Slice<number>,
|
|
130
|
+
): [$.Slice<number>, $.GoError] {
|
|
131
|
+
return open(
|
|
132
|
+
dst,
|
|
133
|
+
nobleXChaCha20Poly1305,
|
|
134
|
+
this.key,
|
|
135
|
+
nonce,
|
|
136
|
+
NonceSizeX,
|
|
137
|
+
ciphertext,
|
|
138
|
+
additionalData,
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function New(key: $.Slice<number>): [AEAD | null, $.GoError] {
|
|
144
|
+
const keyBytes = bytes(key)
|
|
145
|
+
if (keyBytes.length !== KeySize) {
|
|
146
|
+
return [null, errors.New('chacha20poly1305: bad key length')]
|
|
147
|
+
}
|
|
148
|
+
return [
|
|
149
|
+
$.interfaceValue<AEAD | null>(
|
|
150
|
+
new chacha20poly1305(keyBytes),
|
|
151
|
+
'*chacha20poly1305.chacha20poly1305',
|
|
152
|
+
),
|
|
153
|
+
null,
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function NewX(key: $.Slice<number>): [AEAD | null, $.GoError] {
|
|
158
|
+
const keyBytes = bytes(key)
|
|
159
|
+
if (keyBytes.length !== KeySize) {
|
|
160
|
+
return [null, errors.New('chacha20poly1305: bad key length')]
|
|
161
|
+
}
|
|
162
|
+
return [
|
|
163
|
+
$.interfaceValue<AEAD | null>(
|
|
164
|
+
new xchacha20poly1305(keyBytes),
|
|
165
|
+
'*chacha20poly1305.xchacha20poly1305',
|
|
166
|
+
),
|
|
167
|
+
null,
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function seal(
|
|
172
|
+
dst: $.Slice<number>,
|
|
173
|
+
cipher: NobleAEAD,
|
|
174
|
+
key: Uint8Array,
|
|
175
|
+
nonce: $.Slice<number>,
|
|
176
|
+
expectedNonceSize: number,
|
|
177
|
+
plaintext: $.Slice<number>,
|
|
178
|
+
additionalData: $.Slice<number>,
|
|
179
|
+
): $.Slice<number> {
|
|
180
|
+
const nonceBytes = bytes(nonce)
|
|
181
|
+
if (nonceBytes.length !== expectedNonceSize) {
|
|
182
|
+
$.panic('chacha20poly1305: bad nonce length passed to Seal')
|
|
183
|
+
}
|
|
184
|
+
const plaintextBytes = bytes(plaintext)
|
|
185
|
+
if (plaintextBytes.length > maxIETFPlaintext) {
|
|
186
|
+
$.panic('chacha20poly1305: plaintext too large')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const sealed = cipher(key, nonceBytes, bytes(additionalData)).encrypt(
|
|
190
|
+
plaintextBytes,
|
|
191
|
+
)
|
|
192
|
+
return appendBytes(dst, sealed)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function open(
|
|
196
|
+
dst: $.Slice<number>,
|
|
197
|
+
cipher: NobleAEAD,
|
|
198
|
+
key: Uint8Array,
|
|
199
|
+
nonce: $.Slice<number>,
|
|
200
|
+
expectedNonceSize: number,
|
|
201
|
+
ciphertext: $.Slice<number>,
|
|
202
|
+
additionalData: $.Slice<number>,
|
|
203
|
+
): [$.Slice<number>, $.GoError] {
|
|
204
|
+
const nonceBytes = bytes(nonce)
|
|
205
|
+
if (nonceBytes.length !== expectedNonceSize) {
|
|
206
|
+
$.panic('chacha20poly1305: bad nonce length passed to Open')
|
|
207
|
+
}
|
|
208
|
+
const ciphertextBytes = bytes(ciphertext)
|
|
209
|
+
if (ciphertextBytes.length < Overhead) {
|
|
210
|
+
return [null, errOpen]
|
|
211
|
+
}
|
|
212
|
+
if (ciphertextBytes.length > maxIETFCiphertext) {
|
|
213
|
+
$.panic('chacha20poly1305: ciphertext too large')
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
return [
|
|
218
|
+
appendBytes(
|
|
219
|
+
dst,
|
|
220
|
+
cipher(key, nonceBytes, bytes(additionalData)).decrypt(ciphertextBytes),
|
|
221
|
+
),
|
|
222
|
+
null,
|
|
223
|
+
]
|
|
224
|
+
} catch {
|
|
225
|
+
return [null, errOpen]
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function bytes(value: $.Slice<number>): Uint8Array {
|
|
230
|
+
return $.bytesToUint8Array(value).slice()
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function appendBytes(
|
|
234
|
+
dst: $.Slice<number>,
|
|
235
|
+
suffix: Uint8Array,
|
|
236
|
+
): $.Slice<number> {
|
|
237
|
+
const prefix = $.bytesToUint8Array(dst)
|
|
238
|
+
if (prefix.length === 0) {
|
|
239
|
+
return suffix.slice()
|
|
240
|
+
}
|
|
241
|
+
const out = new Uint8Array(prefix.length + suffix.length)
|
|
242
|
+
out.set(prefix)
|
|
243
|
+
out.set(suffix, prefix.length)
|
|
244
|
+
return out
|
|
245
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest'
|
|
2
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
3
|
+
|
|
4
|
+
import { Key } from './index.js'
|
|
5
|
+
|
|
6
|
+
describe('scrypt override', () => {
|
|
7
|
+
test('matches Go scrypt vectors', async () => {
|
|
8
|
+
const vectors = [
|
|
9
|
+
{
|
|
10
|
+
password: 'password',
|
|
11
|
+
salt: 'salt',
|
|
12
|
+
N: 2,
|
|
13
|
+
r: 10,
|
|
14
|
+
p: 10,
|
|
15
|
+
output:
|
|
16
|
+
'482c858e229055e62f41e0ec819a5ee18bdb87251a534f75acd95ac5e50aa15f',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
password: 'p',
|
|
20
|
+
salt: 's',
|
|
21
|
+
N: 2,
|
|
22
|
+
r: 1,
|
|
23
|
+
p: 1,
|
|
24
|
+
output: '48b0d2a8a3272611984c50ebd630af52',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
password: '',
|
|
28
|
+
salt: '',
|
|
29
|
+
N: 16,
|
|
30
|
+
r: 1,
|
|
31
|
+
p: 1,
|
|
32
|
+
output:
|
|
33
|
+
'77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906',
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
for (const vector of vectors) {
|
|
38
|
+
const [key, err] = await Key(
|
|
39
|
+
$.stringToBytes(vector.password),
|
|
40
|
+
$.stringToBytes(vector.salt),
|
|
41
|
+
vector.N,
|
|
42
|
+
vector.r,
|
|
43
|
+
vector.p,
|
|
44
|
+
vector.output.length / 2,
|
|
45
|
+
)
|
|
46
|
+
expect(err).toBeNull()
|
|
47
|
+
expect(toHex(key)).toBe(vector.output)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('validates invalid parameters like Go', async () => {
|
|
52
|
+
const invalid = [
|
|
53
|
+
[0, 1, 1, 'scrypt: N must be > 1 and a power of 2'],
|
|
54
|
+
[1, 1, 1, 'scrypt: N must be > 1 and a power of 2'],
|
|
55
|
+
[7, 8, 1, 'scrypt: N must be > 1 and a power of 2'],
|
|
56
|
+
[2, 0, 1, 'scrypt: parameters must be > 0'],
|
|
57
|
+
[2, 1, 0, 'scrypt: parameters must be > 0'],
|
|
58
|
+
[2, -1, 1, 'scrypt: parameters must be > 0'],
|
|
59
|
+
[2, 1, -1, 'scrypt: parameters must be > 0'],
|
|
60
|
+
] as const
|
|
61
|
+
|
|
62
|
+
for (const [N, r, p, message] of invalid) {
|
|
63
|
+
const [key, err] = await Key(
|
|
64
|
+
$.stringToBytes('p'),
|
|
65
|
+
$.stringToBytes('s'),
|
|
66
|
+
N,
|
|
67
|
+
r,
|
|
68
|
+
p,
|
|
69
|
+
32,
|
|
70
|
+
)
|
|
71
|
+
expect(key).toBeNull()
|
|
72
|
+
expect(err?.Error()).toBe(message)
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
function toHex(input: Uint8Array | number[] | null): string {
|
|
78
|
+
return Array.from(input ?? [])
|
|
79
|
+
.map((value) => value.toString(16).padStart(2, '0'))
|
|
80
|
+
.join('')
|
|
81
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
2
|
+
import * as errors from '@goscript/errors/index.js'
|
|
3
|
+
import { scryptAsync } from '@noble/hashes/scrypt.js'
|
|
4
|
+
|
|
5
|
+
const maxInt = Number.MAX_SAFE_INTEGER
|
|
6
|
+
|
|
7
|
+
export async function Key(
|
|
8
|
+
password: $.Bytes,
|
|
9
|
+
salt: $.Bytes,
|
|
10
|
+
N: number,
|
|
11
|
+
r: number,
|
|
12
|
+
p: number,
|
|
13
|
+
keyLen: number,
|
|
14
|
+
): Promise<[$.Bytes, $.GoError]> {
|
|
15
|
+
if (N <= 1 || (N & (N - 1)) !== 0) {
|
|
16
|
+
return [null, errors.New('scrypt: N must be > 1 and a power of 2')]
|
|
17
|
+
}
|
|
18
|
+
if (r <= 0 || p <= 0) {
|
|
19
|
+
return [null, errors.New('scrypt: parameters must be > 0')]
|
|
20
|
+
}
|
|
21
|
+
if (
|
|
22
|
+
r * p >= 1 << 30 ||
|
|
23
|
+
r > maxInt / 128 / p ||
|
|
24
|
+
r > maxInt / 256 ||
|
|
25
|
+
N > maxInt / 128 / r
|
|
26
|
+
) {
|
|
27
|
+
return [null, errors.New('scrypt: parameters are too large')]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const derived = await scryptAsync(
|
|
32
|
+
$.bytesToUint8Array(password),
|
|
33
|
+
$.bytesToUint8Array(salt),
|
|
34
|
+
{
|
|
35
|
+
N,
|
|
36
|
+
r,
|
|
37
|
+
p,
|
|
38
|
+
dkLen: keyLen,
|
|
39
|
+
asyncTick: 8,
|
|
40
|
+
maxmem: maxInt,
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
return [new Uint8Array(derived), null]
|
|
44
|
+
} catch (err) {
|
|
45
|
+
return [null, errors.New(`scrypt: ${errorMessage(err)}`)]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function errorMessage(err: unknown): string {
|
|
50
|
+
if (err instanceof Error) {
|
|
51
|
+
return err.message
|
|
52
|
+
}
|
|
53
|
+
return String(err)
|
|
54
|
+
}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
|
|
3
3
|
import * as $ from '../../builtin/index.js'
|
|
4
|
-
import {
|
|
5
|
-
New128,
|
|
6
|
-
New128a,
|
|
7
|
-
New32,
|
|
8
|
-
New32a,
|
|
9
|
-
New64,
|
|
10
|
-
New64a,
|
|
11
|
-
} from './index.js'
|
|
4
|
+
import { New128, New128a, New32, New32a, New64, New64a } from './index.js'
|
|
12
5
|
|
|
13
6
|
describe('hash/fnv override', () => {
|
|
14
7
|
it('matches Go FNV sums for hello', async () => {
|
package/gs/hash/fnv/index.ts
CHANGED
|
@@ -65,7 +65,10 @@ class FNV32 {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
|
|
68
|
-
return [
|
|
68
|
+
return [
|
|
69
|
+
appendBytes($.bytesToUint8Array(prefix), this.magic, be32(this.hash)),
|
|
70
|
+
null,
|
|
71
|
+
]
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
MarshalBinary(): [$.Bytes, $.GoError] {
|
|
@@ -136,7 +139,10 @@ class FNV64 {
|
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
|
|
139
|
-
return [
|
|
142
|
+
return [
|
|
143
|
+
appendBytes($.bytesToUint8Array(prefix), this.magic, be64(this.hash)),
|
|
144
|
+
null,
|
|
145
|
+
]
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
MarshalBinary(): [$.Bytes, $.GoError] {
|
|
@@ -185,7 +191,11 @@ class FNV128 {
|
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
async Sum(prefix: $.Bytes | null): Promise<$.Bytes> {
|
|
188
|
-
return appendBytes(
|
|
194
|
+
return appendBytes(
|
|
195
|
+
$.bytesToUint8Array(prefix),
|
|
196
|
+
be64(this.high()),
|
|
197
|
+
be64(this.low()),
|
|
198
|
+
)
|
|
189
199
|
}
|
|
190
200
|
|
|
191
201
|
Reset(): void {
|
|
@@ -202,7 +212,12 @@ class FNV128 {
|
|
|
202
212
|
|
|
203
213
|
AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
|
|
204
214
|
return [
|
|
205
|
-
appendBytes(
|
|
215
|
+
appendBytes(
|
|
216
|
+
$.bytesToUint8Array(prefix),
|
|
217
|
+
this.magic,
|
|
218
|
+
be64(this.high()),
|
|
219
|
+
be64(this.low()),
|
|
220
|
+
),
|
|
206
221
|
null,
|
|
207
222
|
]
|
|
208
223
|
}
|
|
@@ -217,7 +232,8 @@ class FNV128 {
|
|
|
217
232
|
if (err != null) {
|
|
218
233
|
return err
|
|
219
234
|
}
|
|
220
|
-
this.hash =
|
|
235
|
+
this.hash =
|
|
236
|
+
((readBE64(state, 4) << 64n) | readBE64(state, 12)) & uint128Mask
|
|
221
237
|
return null
|
|
222
238
|
}
|
|
223
239
|
|
|
@@ -304,11 +320,12 @@ function be64(value: bigint): Uint8Array {
|
|
|
304
320
|
|
|
305
321
|
function readBE32(bytes: Uint8Array, offset: number): number {
|
|
306
322
|
return (
|
|
307
|
-
((bytes[offset] << 24) >>> 0) |
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
323
|
+
(((bytes[offset] << 24) >>> 0) |
|
|
324
|
+
(bytes[offset + 1] << 16) |
|
|
325
|
+
(bytes[offset + 2] << 8) |
|
|
326
|
+
bytes[offset + 3]) >>>
|
|
327
|
+
0
|
|
328
|
+
)
|
|
312
329
|
}
|
|
313
330
|
|
|
314
331
|
function readBE64(bytes: Uint8Array, offset: number): bigint {
|
package/gs/io/fs/glob.ts
CHANGED
|
@@ -60,15 +60,18 @@ $.registerInterfaceType(
|
|
|
60
60
|
// If fs implements [GlobFS], Glob calls fs.Glob.
|
|
61
61
|
// Otherwise, Glob uses [ReadDir] to traverse the directory tree
|
|
62
62
|
// and look for matches for the pattern.
|
|
63
|
-
export function Glob(
|
|
64
|
-
|
|
63
|
+
export async function Glob(
|
|
64
|
+
fsys: FS,
|
|
65
|
+
pattern: string,
|
|
66
|
+
): Promise<[$.Slice<string>, $.GoError]> {
|
|
67
|
+
return await globWithLimit(fsys, pattern, 0)
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
export function globWithLimit(
|
|
70
|
+
export async function globWithLimit(
|
|
68
71
|
fsys: FS,
|
|
69
72
|
pattern: string,
|
|
70
73
|
depth: number,
|
|
71
|
-
): [$.Slice<string>, $.GoError] {
|
|
74
|
+
): Promise<[$.Slice<string>, $.GoError]> {
|
|
72
75
|
let matches: $.Slice<string> = null
|
|
73
76
|
{
|
|
74
77
|
// This limit is added to prevent stack exhaustion issues. See
|
|
@@ -105,7 +108,7 @@ export function globWithLimit(
|
|
|
105
108
|
dir = cleanGlobPath(dir)
|
|
106
109
|
|
|
107
110
|
if (!hasMeta(dir)) {
|
|
108
|
-
return glob(fsys, dir, file, null)
|
|
111
|
+
return await glob(fsys, dir, file, null)
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
// Prevent infinite recursion. See issue 15879.
|
|
@@ -113,14 +116,14 @@ export function globWithLimit(
|
|
|
113
116
|
return [null, path.ErrBadPattern]
|
|
114
117
|
}
|
|
115
118
|
|
|
116
|
-
const [dirs, dirErr] = globWithLimit(fsys, dir, depth + 1)
|
|
119
|
+
const [dirs, dirErr] = await globWithLimit(fsys, dir, depth + 1)
|
|
117
120
|
if (dirErr != null) {
|
|
118
121
|
return [null, dirErr]
|
|
119
122
|
}
|
|
120
123
|
for (let _i = 0; _i < $.len(dirs); _i++) {
|
|
121
124
|
const d = dirs![_i]
|
|
122
125
|
{
|
|
123
|
-
const [nextMatches, globErr] = glob(fsys, d, file, matches)
|
|
126
|
+
const [nextMatches, globErr] = await glob(fsys, d, file, matches)
|
|
124
127
|
matches = nextMatches
|
|
125
128
|
if (globErr != null) {
|
|
126
129
|
return [matches, globErr]
|
|
@@ -148,15 +151,15 @@ export function cleanGlobPath(path: string): string {
|
|
|
148
151
|
// and appends them to matches, returning the updated slice.
|
|
149
152
|
// If the directory cannot be opened, glob returns the existing matches.
|
|
150
153
|
// New matches are added in lexicographical order.
|
|
151
|
-
export function glob(
|
|
154
|
+
export async function glob(
|
|
152
155
|
fs: FS,
|
|
153
156
|
dir: string,
|
|
154
157
|
pattern: string,
|
|
155
158
|
matches: $.Slice<string>,
|
|
156
|
-
): [$.Slice<string>, $.GoError] {
|
|
159
|
+
): Promise<[$.Slice<string>, $.GoError]> {
|
|
157
160
|
let m = matches
|
|
158
161
|
{
|
|
159
|
-
let [infos, err] = ReadDir(fs, dir)
|
|
162
|
+
let [infos, err] = await ReadDir(fs, dir)
|
|
160
163
|
|
|
161
164
|
// ignore I/O error
|
|
162
165
|
if (err != null) {
|
package/gs/io/fs/meta.json
CHANGED
package/gs/io/fs/readdir.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as $ from '@goscript/builtin/index.js'
|
|
|
4
4
|
import { File, FileInfo, ReadDir } from './index.js'
|
|
5
5
|
|
|
6
6
|
describe('io/fs ReadDir override', () => {
|
|
7
|
-
it('returns a nil entry slice without sorting when directory read fails', () => {
|
|
7
|
+
it('returns a nil entry slice without sorting when directory read fails', async () => {
|
|
8
8
|
const readErr = $.newError('read failed')
|
|
9
9
|
const file: File & {
|
|
10
10
|
ReadDir(n: number): [null, $.GoError]
|
|
@@ -23,7 +23,7 @@ describe('io/fs ReadDir override', () => {
|
|
|
23
23
|
},
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const [list, err] = ReadDir(
|
|
26
|
+
const [list, err] = await ReadDir(
|
|
27
27
|
{
|
|
28
28
|
Open(_name: string): [File, $.GoError] {
|
|
29
29
|
return [file, null]
|
|
@@ -35,4 +35,65 @@ describe('io/fs ReadDir override', () => {
|
|
|
35
35
|
expect(list).toBeNull()
|
|
36
36
|
expect(err).toBe(readErr)
|
|
37
37
|
})
|
|
38
|
+
|
|
39
|
+
it('awaits async FS.Open fallback implementations', async () => {
|
|
40
|
+
const entries = [
|
|
41
|
+
{
|
|
42
|
+
Name(): string {
|
|
43
|
+
return 'b.txt'
|
|
44
|
+
},
|
|
45
|
+
IsDir(): boolean {
|
|
46
|
+
return false
|
|
47
|
+
},
|
|
48
|
+
Info(): [FileInfo, $.GoError] {
|
|
49
|
+
return [null, null]
|
|
50
|
+
},
|
|
51
|
+
Type(): number {
|
|
52
|
+
return 0
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
Name(): string {
|
|
57
|
+
return 'a.txt'
|
|
58
|
+
},
|
|
59
|
+
IsDir(): boolean {
|
|
60
|
+
return false
|
|
61
|
+
},
|
|
62
|
+
Info(): [FileInfo, $.GoError] {
|
|
63
|
+
return [null, null]
|
|
64
|
+
},
|
|
65
|
+
Type(): number {
|
|
66
|
+
return 0
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
const file: File & {
|
|
71
|
+
ReadDir(n: number): Promise<[$.Slice<any>, $.GoError]>
|
|
72
|
+
} = {
|
|
73
|
+
Close(): $.GoError {
|
|
74
|
+
return null
|
|
75
|
+
},
|
|
76
|
+
Read(_p0: Uint8Array): [number, $.GoError] {
|
|
77
|
+
return [0, null]
|
|
78
|
+
},
|
|
79
|
+
Stat(): [FileInfo, $.GoError] {
|
|
80
|
+
return [null, null]
|
|
81
|
+
},
|
|
82
|
+
async ReadDir(_n: number): Promise<[$.Slice<any>, $.GoError]> {
|
|
83
|
+
return [$.arrayToSlice(entries), null]
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const [list, err] = await ReadDir(
|
|
88
|
+
{
|
|
89
|
+
async Open(_name: string): Promise<[File, $.GoError]> {
|
|
90
|
+
return [file, null]
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
'dir',
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
expect(err).toBeNull()
|
|
97
|
+
expect(list?.map((entry) => entry?.Name())).toEqual(['a.txt', 'b.txt'])
|
|
98
|
+
})
|
|
38
99
|
})
|