@quenty/secrets 7.23.0 → 7.23.2-canary.547.11ae689.0
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/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [7.23.2-canary.547.11ae689.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/secrets@7.23.0...@quenty/secrets@7.23.2-canary.547.11ae689.0) (2025-04-07)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Add types to packages ([2374fb2](https://github.com/Quenty/NevermoreEngine/commit/2374fb2b043cfbe0e9b507b3316eec46a4e353a0))
|
|
12
|
+
* Bump package versions for republishing ([ba47c62](https://github.com/Quenty/NevermoreEngine/commit/ba47c62e32170bf74377b0c658c60b84306dc294))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## [7.23.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/secrets@7.23.0...@quenty/secrets@7.23.1) (2025-04-07)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* Add types to packages ([2374fb2](https://github.com/Quenty/NevermoreEngine/commit/2374fb2b043cfbe0e9b507b3316eec46a4e353a0))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
6
29
|
# [7.23.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/secrets@7.22.5...@quenty/secrets@7.23.0) (2025-04-02)
|
|
7
30
|
|
|
8
31
|
**Note:** Version bump only for package @quenty/secrets
|
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2014-
|
|
3
|
+
Copyright (c) 2014-2025 James Onnen (Quenty)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/secrets",
|
|
3
|
-
"version": "7.23.0",
|
|
3
|
+
"version": "7.23.2-canary.547.11ae689.0",
|
|
4
4
|
"description": "Secrets storage system and API surface",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,21 +25,21 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/cmdrservice": "
|
|
29
|
-
"@quenty/datastore": "
|
|
30
|
-
"@quenty/ellipticcurvecryptography": "
|
|
31
|
-
"@quenty/loader": "
|
|
32
|
-
"@quenty/maid": "
|
|
33
|
-
"@quenty/permissionprovider": "
|
|
34
|
-
"@quenty/promise": "
|
|
35
|
-
"@quenty/remotefunctionutils": "
|
|
36
|
-
"@quenty/remoting": "
|
|
37
|
-
"@quenty/rx": "
|
|
38
|
-
"@quenty/servicebag": "
|
|
39
|
-
"@quenty/table": "
|
|
28
|
+
"@quenty/cmdrservice": "13.22.2-canary.547.11ae689.0",
|
|
29
|
+
"@quenty/datastore": "13.20.2-canary.547.11ae689.0",
|
|
30
|
+
"@quenty/ellipticcurvecryptography": "1.6.2-canary.547.11ae689.0",
|
|
31
|
+
"@quenty/loader": "10.8.2-canary.547.11ae689.0",
|
|
32
|
+
"@quenty/maid": "3.4.2-canary.547.11ae689.0",
|
|
33
|
+
"@quenty/permissionprovider": "14.19.2-canary.547.11ae689.0",
|
|
34
|
+
"@quenty/promise": "10.10.3-canary.547.11ae689.0",
|
|
35
|
+
"@quenty/remotefunctionutils": "10.10.3-canary.547.11ae689.0",
|
|
36
|
+
"@quenty/remoting": "12.18.2-canary.547.11ae689.0",
|
|
37
|
+
"@quenty/rx": "13.17.2-canary.547.11ae689.0",
|
|
38
|
+
"@quenty/servicebag": "11.11.3-canary.547.11ae689.0",
|
|
39
|
+
"@quenty/table": "3.7.3-canary.547.11ae689.0"
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "11ae6894c9c40c596e521dc1d2a71977af63752f"
|
|
45
45
|
}
|
|
@@ -10,11 +10,12 @@ local SecretsCmdrTypeUtils = require("SecretsCmdrTypeUtils")
|
|
|
10
10
|
local SecretsServiceConstants = require("SecretsServiceConstants")
|
|
11
11
|
local RemoteFunctionUtils = require("RemoteFunctionUtils")
|
|
12
12
|
local Promise = require("Promise")
|
|
13
|
+
local _ServiceBag = require("ServiceBag")
|
|
13
14
|
|
|
14
15
|
local SecretsServiceClient = {}
|
|
15
16
|
SecretsServiceClient.ServiceName = "SecretsServiceClient"
|
|
16
17
|
|
|
17
|
-
function SecretsServiceClient:Init(serviceBag)
|
|
18
|
+
function SecretsServiceClient:Init(serviceBag: _ServiceBag.ServiceBag)
|
|
18
19
|
assert(not self._serviceBag, "Already initialized")
|
|
19
20
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
20
21
|
self._maid = Maid.new()
|
|
@@ -6,17 +6,18 @@ local require = require(script.Parent.loader).load(script)
|
|
|
6
6
|
|
|
7
7
|
local SecretsCmdrTypeUtils = require("SecretsCmdrTypeUtils")
|
|
8
8
|
local Maid = require("Maid")
|
|
9
|
+
local _ServiceBag = require("ServiceBag")
|
|
9
10
|
|
|
10
11
|
local SecretsCommandService = {}
|
|
11
12
|
SecretsCommandService.ServiceName = "SecretsCommandService"
|
|
12
13
|
|
|
13
|
-
function SecretsCommandService:Init(serviceBag)
|
|
14
|
+
function SecretsCommandService:Init(serviceBag: _ServiceBag.ServiceBag)
|
|
14
15
|
assert(not self._serviceBag, "Already initialized")
|
|
15
16
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
16
17
|
self._maid = Maid.new()
|
|
17
18
|
|
|
18
19
|
self._cmdrService = self._serviceBag:GetService(require("CmdrService"))
|
|
19
|
-
self._secretsService = self._serviceBag:GetService(require("SecretsService"))
|
|
20
|
+
self._secretsService = self._serviceBag:GetService((require :: any)("SecretsService"))
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
function SecretsCommandService:Start()
|
|
@@ -123,14 +124,14 @@ function SecretsCommandService:_registerCommands()
|
|
|
123
124
|
|
|
124
125
|
local maxKeyLength = 6
|
|
125
126
|
local maxValueLength = 5
|
|
126
|
-
for key, value in
|
|
127
|
+
for key, value in secrets do
|
|
127
128
|
maxKeyLength = math.max(maxKeyLength, #key)
|
|
128
129
|
maxValueLength = math.max(maxValueLength, #value)
|
|
129
130
|
end
|
|
130
131
|
|
|
131
132
|
local output = string.format("\n%-" .. maxKeyLength .. "s %-" .. maxValueLength .. "s", "Secret", "Value")
|
|
132
133
|
output = output .. string.format("\n%s %s", string.rep("-", maxKeyLength), string.rep("-", maxValueLength))
|
|
133
|
-
for key, value in
|
|
134
|
+
for key, value in secrets do
|
|
134
135
|
output = output .. string.format("\n%-" .. maxKeyLength .. "s %-" .. maxValueLength .. "s", key, value)
|
|
135
136
|
end
|
|
136
137
|
output = output .. string.format("\n%s %s", string.rep("-", maxKeyLength), string.rep("-", maxValueLength))
|
|
@@ -10,11 +10,12 @@ local GetRemoteFunction = require("GetRemoteFunction")
|
|
|
10
10
|
local Promise = require("Promise")
|
|
11
11
|
local Observable = require("Observable")
|
|
12
12
|
local EllipticCurveCryptography = require("EllipticCurveCryptography")
|
|
13
|
+
local _ServiceBag = require("ServiceBag")
|
|
13
14
|
|
|
14
15
|
local SecretsService = {}
|
|
15
16
|
SecretsService.ServiceName = "SecretsService"
|
|
16
17
|
|
|
17
|
-
function SecretsService:Init(serviceBag)
|
|
18
|
+
function SecretsService:Init(serviceBag: _ServiceBag.ServiceBag)
|
|
18
19
|
assert(not self._serviceBag, "Already initialized")
|
|
19
20
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
20
21
|
self._maid = Maid.new()
|
|
@@ -39,7 +40,7 @@ end
|
|
|
39
40
|
|
|
40
41
|
@param seed number
|
|
41
42
|
]=]
|
|
42
|
-
function SecretsService:SetPublicKeySeed(seed)
|
|
43
|
+
function SecretsService:SetPublicKeySeed(seed: number)
|
|
43
44
|
assert(type(seed) == "number", "Bad seed")
|
|
44
45
|
|
|
45
46
|
local private, public = EllipticCurveCryptography.keypair(seed or EllipticCurveCryptography.random.random())
|
|
@@ -64,23 +65,22 @@ end
|
|
|
64
65
|
@param secretKey string
|
|
65
66
|
@return Promise<string>
|
|
66
67
|
]=]
|
|
67
|
-
function SecretsService:PromiseSecret(secretKey)
|
|
68
|
+
function SecretsService:PromiseSecret(secretKey: string)
|
|
68
69
|
assert(type(secretKey) == "string", "Bad secretKey")
|
|
69
70
|
|
|
70
71
|
return self:_promiseSubstore():Then(function(substore)
|
|
71
|
-
return self._maid:GivePromise(substore:Load(secretKey))
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
return self._maid:GivePromise(substore:Load(secretKey)):Then(function(data)
|
|
73
|
+
if type(data) ~= "table" then
|
|
74
|
+
return Promise.resolved(nil)
|
|
75
|
+
else
|
|
76
|
+
local ok, value = self:_decrypt(data)
|
|
77
|
+
if ok then
|
|
78
|
+
return value
|
|
75
79
|
else
|
|
76
|
-
|
|
77
|
-
if ok then
|
|
78
|
-
return value
|
|
79
|
-
else
|
|
80
|
-
return Promise.rejected(value or "Failed to decrypt result")
|
|
81
|
-
end
|
|
80
|
+
return Promise.rejected(value or "Failed to decrypt result")
|
|
82
81
|
end
|
|
83
|
-
end
|
|
82
|
+
end
|
|
83
|
+
end)
|
|
84
84
|
end)
|
|
85
85
|
end
|
|
86
86
|
|
|
@@ -89,23 +89,22 @@ end
|
|
|
89
89
|
|
|
90
90
|
@return @return Promise<{string}>
|
|
91
91
|
]=]
|
|
92
|
-
function SecretsService:PromiseAllSecrets()
|
|
92
|
+
function SecretsService:PromiseAllSecrets(): Promise.Promise<{ string }>
|
|
93
93
|
return self:_promiseSubstore():Then(function(substore)
|
|
94
|
-
return self._maid:GivePromise(substore:LoadAll())
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
warn(string.format("[SecretsService] - Failed to decrypt %q", key))
|
|
104
|
-
end
|
|
94
|
+
return self._maid:GivePromise(substore:LoadAll()):Then(function(secretsList)
|
|
95
|
+
local secretMap = {}
|
|
96
|
+
|
|
97
|
+
for key, secretData in secretsList do
|
|
98
|
+
local ok, decrypted = self:_decrypt(secretData)
|
|
99
|
+
if ok then
|
|
100
|
+
secretMap[key] = decrypted
|
|
101
|
+
else
|
|
102
|
+
warn(string.format("[SecretsService] - Failed to decrypt %q", key))
|
|
105
103
|
end
|
|
104
|
+
end
|
|
106
105
|
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
return secretMap
|
|
107
|
+
end)
|
|
109
108
|
end)
|
|
110
109
|
end
|
|
111
110
|
|
|
@@ -115,26 +114,29 @@ end
|
|
|
115
114
|
@param secretKey string
|
|
116
115
|
@return Observable<string>
|
|
117
116
|
]=]
|
|
118
|
-
function SecretsService:ObserveSecret(secretKey)
|
|
117
|
+
function SecretsService:ObserveSecret(secretKey: string): Observable.Observable<string>
|
|
119
118
|
assert(type(secretKey) == "string", "Bad secretKey")
|
|
120
119
|
|
|
121
120
|
return Observable.new(function(sub)
|
|
122
121
|
local maid = Maid.new()
|
|
123
122
|
|
|
124
123
|
maid:GivePromise(self:_promiseSubstore():Then(function(substore)
|
|
125
|
-
maid:GivePromise(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
local ok, value = self:_decrypt(data)
|
|
130
|
-
if ok then
|
|
131
|
-
sub:Fire(value)
|
|
124
|
+
maid:GivePromise(
|
|
125
|
+
substore:Observe(secretKey):Subscribe(function(data)
|
|
126
|
+
if type(data) ~= "table" then
|
|
127
|
+
sub:Fire(nil)
|
|
132
128
|
else
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
local ok, value = self:_decrypt(data)
|
|
130
|
+
if ok then
|
|
131
|
+
sub:Fire(value)
|
|
132
|
+
else
|
|
133
|
+
-- TODO: Maybe brio instead?
|
|
134
|
+
sub:Fail(value or "Failed to decrypt result")
|
|
135
|
+
end
|
|
135
136
|
end
|
|
136
|
-
end
|
|
137
|
-
|
|
137
|
+
end),
|
|
138
|
+
sub:GetFailComplete()
|
|
139
|
+
)
|
|
138
140
|
end, function(err)
|
|
139
141
|
sub:Fail(err or "Failed to get datastore")
|
|
140
142
|
end))
|
|
@@ -148,10 +150,10 @@ end
|
|
|
148
150
|
|
|
149
151
|
@param secretKey string
|
|
150
152
|
]=]
|
|
151
|
-
function SecretsService:DeleteSecret(secretKey)
|
|
153
|
+
function SecretsService:DeleteSecret(secretKey: string): Promise.Promise<()>
|
|
152
154
|
assert(type(secretKey) == "string", "Bad secretKey")
|
|
153
155
|
|
|
154
|
-
self:_promiseSubstore():Then(function(substore)
|
|
156
|
+
return self:_promiseSubstore():Then(function(substore)
|
|
155
157
|
substore:Delete(secretKey)
|
|
156
158
|
end)
|
|
157
159
|
end
|
|
@@ -162,7 +164,7 @@ end
|
|
|
162
164
|
@param secretKey string
|
|
163
165
|
@param value string
|
|
164
166
|
]=]
|
|
165
|
-
function SecretsService:StoreSecret(secretKey, value)
|
|
167
|
+
function SecretsService:StoreSecret(secretKey: string, value: string)
|
|
166
168
|
assert(type(secretKey) == "string", "Bad secretKey")
|
|
167
169
|
assert(type(value) == "string", "Bad value")
|
|
168
170
|
|
|
@@ -174,8 +176,8 @@ function SecretsService:StoreSecret(secretKey, value)
|
|
|
174
176
|
|
|
175
177
|
-- TODO: Encode byte array in more efficient structure for JSON
|
|
176
178
|
local toStore = {
|
|
177
|
-
encrypted = setmetatable(table.clone(encrypted), nil)
|
|
178
|
-
signature = setmetatable(table.clone(signature), nil)
|
|
179
|
+
encrypted = setmetatable(table.clone(encrypted), nil), -- remove metatable
|
|
180
|
+
signature = setmetatable(table.clone(signature), nil), -- remove metatable
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
substore:Store(secretKey, toStore)
|
|
@@ -185,9 +187,9 @@ end
|
|
|
185
187
|
--[=[
|
|
186
188
|
Clears all the secrets stored in the datastore
|
|
187
189
|
|
|
188
|
-
@return
|
|
190
|
+
@return Promise<()>
|
|
189
191
|
]=]
|
|
190
|
-
function SecretsService:ClearAllSecrets()
|
|
192
|
+
function SecretsService:ClearAllSecrets(): Promise.Promise<()>
|
|
191
193
|
return self:_promiseSubstore():Then(function(substore)
|
|
192
194
|
return substore:Wipe()
|
|
193
195
|
end)
|
|
@@ -196,9 +198,9 @@ end
|
|
|
196
198
|
--[=[
|
|
197
199
|
Gets a list of all available secret keys for the game
|
|
198
200
|
|
|
199
|
-
@return { string }
|
|
201
|
+
@return Promise<{ string }>
|
|
200
202
|
]=]
|
|
201
|
-
function SecretsService:PromiseSecretKeyNamesList()
|
|
203
|
+
function SecretsService:PromiseSecretKeyNamesList(): Promise.Promise<{ string }>
|
|
202
204
|
return self:_promiseSubstore():Then(function(substore)
|
|
203
205
|
return substore:PromiseKeyList()
|
|
204
206
|
end)
|
|
@@ -211,16 +213,24 @@ function SecretsService:_warnAboutNoPublicKeyStoredInSourceCode()
|
|
|
211
213
|
end
|
|
212
214
|
end
|
|
213
215
|
|
|
214
|
-
function SecretsService:_getInstructions()
|
|
215
|
-
local instructions =
|
|
216
|
+
function SecretsService:_getInstructions(): string
|
|
217
|
+
local instructions =
|
|
218
|
+
"[SecretsService.StoreSecret] - Security - Current private key seed is GameId, which is guessable."
|
|
216
219
|
instructions = instructions .. "\n\tTIP: This is only applicable if we're storing API keys for use in here."
|
|
217
|
-
instructions = instructions
|
|
218
|
-
|
|
220
|
+
instructions = instructions
|
|
221
|
+
.. "\n\tTIP: If you set the private key seed in source code, attackers need source code AND datastore access"
|
|
222
|
+
instructions = instructions
|
|
223
|
+
.. '\n\tTIP: Call `serviceBag:GetService(require("SecretsService")):SetPublicKeySeed(UNIQUE_RANDOM_NUMBER_HERE)` to suppress this warning.'
|
|
219
224
|
instructions = instructions .. "\n\tTIP: This will invalidate previous secrets stored."
|
|
220
225
|
return instructions
|
|
221
226
|
end
|
|
222
227
|
|
|
223
|
-
|
|
228
|
+
export type SecretsData = {
|
|
229
|
+
encrypted: { number },
|
|
230
|
+
signature: { number },
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function SecretsService:_decrypt(data: SecretsData): (boolean?, string)
|
|
224
234
|
assert(type(data) == "table", "Bad data")
|
|
225
235
|
assert(data.encrypted ~= nil, "Bad data.encrypted")
|
|
226
236
|
assert(data.signature ~= nil, "Bad data.signature")
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
@class SecretsCmdrTypeUtils
|
|
3
3
|
]=]
|
|
4
4
|
|
|
5
|
-
local require = require(script.Parent.loader).load(script)
|
|
6
|
-
|
|
7
5
|
local SecretsCmdrTypeUtils = {}
|
|
8
6
|
|
|
9
7
|
function SecretsCmdrTypeUtils.registerSecretKeyTypes(cmdr, secretsService)
|
|
@@ -19,7 +17,7 @@ end
|
|
|
19
17
|
function SecretsCmdrTypeUtils.makeSecretKeyType(cmdr, secretsService, isRequired)
|
|
20
18
|
return {
|
|
21
19
|
Transform = function(text)
|
|
22
|
-
|
|
20
|
+
local secretNames = secretsService:PromiseSecretKeyNamesList():Wait()
|
|
23
21
|
local list
|
|
24
22
|
if not isRequired then
|
|
25
23
|
list = table.clone(secretNames)
|