@voxgig/sdkgen 4.30.2 → 4.31.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/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/ReadmeTop.js +6 -5
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/definitionPlan.d.ts +27 -0
- package/dist/helpers/definitionPlan.js +219 -0
- package/dist/helpers/definitionPlan.js.map +1 -0
- package/dist/helpers/naming.d.ts +2 -1
- package/dist/helpers/naming.js +13 -4
- package/dist/helpers/naming.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -2
- package/dist/sdkgen.js +6 -3
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/project/.sdk/src/cmp/c/PrepareAuth_c.ts +5 -3
- package/project/.sdk/src/cmp/clojure/PrepareAuth_clojure.ts +7 -5
- package/project/.sdk/src/cmp/cpp/PrepareAuth_cpp.ts +5 -3
- package/project/.sdk/src/cmp/csharp/PrepareAuth_csharp.ts +6 -4
- package/project/.sdk/src/cmp/elixir/PrepareAuth_elixir.ts +8 -6
- package/project/.sdk/src/cmp/go/PrepareAuth_go.ts +7 -9
- package/project/.sdk/src/cmp/java/PrepareAuth_java.ts +5 -3
- package/project/.sdk/src/cmp/js/PrepareAuth_js.ts +6 -4
- package/project/.sdk/src/cmp/js/ReadmeInstall_js.ts +22 -5
- package/project/.sdk/src/cmp/js/TestDefinition_js.ts +40 -0
- package/project/.sdk/src/cmp/js/Test_js.ts +2 -0
- package/project/.sdk/src/cmp/kotlin/PrepareAuth_kotlin.ts +5 -3
- package/project/.sdk/src/cmp/lua/PrepareAuth_lua.ts +7 -3
- package/project/.sdk/src/cmp/ocaml/PrepareAuth_ocaml.ts +7 -5
- package/project/.sdk/src/cmp/perl/PrepareAuth_perl.ts +6 -3
- package/project/.sdk/src/cmp/php/PrepareAuth_php.ts +5 -3
- package/project/.sdk/src/cmp/php/ReadmeInstall_php.ts +11 -5
- package/project/.sdk/src/cmp/py/PrepareAuth_py.ts +5 -3
- package/project/.sdk/src/cmp/rb/PrepareAuth_rb.ts +5 -3
- package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +14 -4
- package/project/.sdk/src/cmp/rust/PrepareAuth_rust.ts +5 -3
- package/project/.sdk/src/cmp/scala/PrepareAuth_scala.ts +5 -3
- package/project/.sdk/src/cmp/swift/PrepareAuth_swift.ts +5 -3
- package/project/.sdk/src/cmp/ts/PrepareAuth_ts.ts +6 -4
- package/project/.sdk/src/cmp/ts/ReadmeInstall_ts.ts +10 -4
- package/project/.sdk/src/cmp/ts/TestDefinition_ts.ts +40 -0
- package/project/.sdk/src/cmp/ts/Test_ts.ts +2 -0
- package/project/.sdk/src/cmp/zig/PrepareAuth_zig.ts +5 -3
- package/project/.sdk/tm/c/utility/prepare_query.c +34 -2
- package/project/.sdk/tm/clojure/src/sdk/core.clj +20 -2
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +31 -2
- package/project/.sdk/tm/csharp/utility/PrepareQuery.cs +32 -4
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +35 -1
- package/project/.sdk/tm/go/utility/prepare_query.go +31 -1
- package/project/.sdk/tm/java/utility/PrepareQuery.java +29 -5
- package/project/.sdk/tm/js/src/utility/PrepareQueryUtility.js +16 -2
- package/project/.sdk/tm/js/test/definition-runner.js +161 -0
- package/project/.sdk/tm/js/test/pipeline.test.js +43 -3
- package/project/.sdk/tm/js/test/sdk-test-control.json +4 -1
- package/project/.sdk/tm/kotlin/utility/Prepare.kt +29 -5
- package/project/.sdk/tm/lua/utility/prepare_query.lua +31 -2
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +22 -1
- package/project/.sdk/tm/perl/utility/prepare_query.pm +25 -2
- package/project/.sdk/tm/php/utility/PrepareQuery.php +28 -1
- package/project/.sdk/tm/py/pkg/utility/prepare_query.py +23 -2
- package/project/.sdk/tm/rb/utility/prepare_query.rb +24 -2
- package/project/.sdk/tm/rust/utility/prepare_query.rs +34 -2
- package/project/.sdk/tm/scala/utility/Prepare.scala +31 -4
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +23 -5
- package/project/.sdk/tm/ts/src/utility/PrepareQueryUtility.ts +16 -2
- package/project/.sdk/tm/ts/test/definition-runner.ts +179 -0
- package/project/.sdk/tm/ts/test/pipeline.test.ts +43 -3
- package/project/.sdk/tm/ts/test/sdk-test-control.json +4 -1
- package/project/.sdk/tm/ts/test/utility.ts +3 -2
- package/project/.sdk/tm/zig/core/utility.zig +29 -1
- package/project/sdkgen-package.json +1 -1
- package/src/cmp/ReadmeTop.ts +7 -6
- package/src/helpers/definitionPlan.ts +265 -0
- package/src/helpers/naming.ts +17 -4
- package/src/sdkgen.ts +4 -1
|
@@ -106,19 +106,21 @@ ${p} (if (= auth-prefix "") apikey-val (str auth-prefix " " apikey-val)
|
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
function basicBlock(): string {
|
|
109
|
-
return ` ;; True HTTP Basic Auth
|
|
110
|
-
;; single token in the header (the branch below) can never
|
|
109
|
+
return ` ;; True HTTP Basic Auth joins the two credentials, base64-encoded -
|
|
110
|
+
;; a single token in the header (the branch below) can never
|
|
111
111
|
;; authenticate against an API that actually checks
|
|
112
|
-
;; \`Authorization: Basic base64(user:pass)\`.
|
|
112
|
+
;; \`Authorization: Basic base64(user:pass)\`. The password may
|
|
113
|
+
;; be empty (RFC 7617): Lob, for one, documents the key as the
|
|
114
|
+
;; user with a blank password (\`curl -u key:\`).
|
|
113
115
|
(if (= true (vs/getpath options "auth.basic"))
|
|
114
116
|
(let [secret (vs/getprop options OPTION-SECRET NOT-FOUND)
|
|
115
117
|
missing? (fn [v] (or (nil? v)
|
|
116
118
|
(and (string? v) (or (= v NOT-FOUND) (= v "")))))]
|
|
117
|
-
(if (
|
|
119
|
+
(if (missing? apikey)
|
|
118
120
|
(vs/delprop headers HEADER-AUTH)
|
|
119
121
|
(let [auth-prefix (or (vs/getpath options "auth.prefix") "")
|
|
120
122
|
b64 (.encodeToString (java.util.Base64/getEncoder)
|
|
121
|
-
(.getBytes ^String (str apikey ":" secret) "UTF-8"))]
|
|
123
|
+
(.getBytes ^String (str apikey ":" (if (missing? secret) "" secret)) "UTF-8"))]
|
|
122
124
|
(.put ^java.util.Map headers HEADER-AUTH
|
|
123
125
|
(if (= auth-prefix "") b64 (str auth-prefix " " b64))))))
|
|
124
126
|
${headerPlace(16)})`
|
|
@@ -165,9 +165,11 @@ ${clear(spec.where, 4)}
|
|
|
165
165
|
`
|
|
166
166
|
|
|
167
167
|
const basicBlock = !withBasic ? '' : `
|
|
168
|
-
// True HTTP Basic Auth
|
|
168
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
169
169
|
// token in the header (the branch below) can never authenticate against
|
|
170
170
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
171
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
172
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
171
173
|
if (is_true(Struct::getpath(options, {"auth", "basic"}))) {
|
|
172
174
|
Value secret = getp(options, "secret", Value(NOT_FOUND));
|
|
173
175
|
|
|
@@ -178,13 +180,13 @@ ${clear(spec.where, 4)}
|
|
|
178
180
|
noSecret = true;
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
if (skip
|
|
183
|
+
if (skip) {
|
|
182
184
|
${clear(spec.where, 6)}
|
|
183
185
|
} else {
|
|
184
186
|
std::string authPrefix = as_str(Struct::getpath(options, {"auth", "prefix"}));
|
|
185
187
|
std::string b64 = authBase64(
|
|
186
188
|
(apikey.is_string() ? apikey.as_string() : "") + ":" +
|
|
187
|
-
(secret.is_string() ? secret.as_string() : ""));
|
|
189
|
+
(!noSecret && secret.is_string() ? secret.as_string() : ""));
|
|
188
190
|
if (authPrefix.empty()) {
|
|
189
191
|
map_put(headers, CRED_NAME, Value(b64));
|
|
190
192
|
} else {
|
|
@@ -92,10 +92,12 @@ function renderHeader(Name: string, cred: string, basic: boolean): string {
|
|
|
92
92
|
private const string OptionSecret = "secret";` : ''
|
|
93
93
|
|
|
94
94
|
const basicBlock = basic ? `
|
|
95
|
-
// True HTTP Basic Auth
|
|
95
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a
|
|
96
96
|
// single token in the header (the branch below) can never
|
|
97
97
|
// authenticate against an API that actually checks
|
|
98
|
-
// \`Authorization: Basic base64(user:pass)\`.
|
|
98
|
+
// \`Authorization: Basic base64(user:pass)\`. The password may be
|
|
99
|
+
// empty (RFC 7617): Lob, for one, documents the key as the user with
|
|
100
|
+
// a blank password (\`curl -u key:\`).
|
|
99
101
|
if (StructUtils.GetPath(options, StructUtils.Jt("auth", "basic")) is bool isBasic &&
|
|
100
102
|
isBasic)
|
|
101
103
|
{
|
|
@@ -106,7 +108,7 @@ function renderHeader(Name: string, cred: string, basic: boolean): string {
|
|
|
106
108
|
var noSecret = secret == null ||
|
|
107
109
|
(secret is string skStr && (skStr == NotFound || skStr == ""));
|
|
108
110
|
|
|
109
|
-
if (noApikey
|
|
111
|
+
if (noApikey)
|
|
110
112
|
{
|
|
111
113
|
headers.Remove(HeaderAuth);
|
|
112
114
|
}
|
|
@@ -118,7 +120,7 @@ function renderHeader(Name: string, cred: string, basic: boolean): string {
|
|
|
118
120
|
basicPrefix = bp;
|
|
119
121
|
}
|
|
120
122
|
var b64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(
|
|
121
|
-
(apikey as string ?? "") + ":" + (secret as string ?? "")));
|
|
123
|
+
(apikey as string ?? "") + ":" + (noSecret ? "" : secret as string ?? "")));
|
|
122
124
|
headers[HeaderAuth] = basicPrefix == ""
|
|
123
125
|
? b64
|
|
124
126
|
: basicPrefix + " " + b64;
|
|
@@ -139,21 +139,23 @@ ${bag}
|
|
|
139
139
|
`
|
|
140
140
|
|
|
141
141
|
const body = basicHere
|
|
142
|
-
? ` # True HTTP Basic Auth
|
|
143
|
-
# token in the header (the branch below) can never
|
|
144
|
-
# against an API that actually checks
|
|
145
|
-
# \`Authorization: Basic base64(user:pass)\`.
|
|
142
|
+
? ` # True HTTP Basic Auth joins the two credentials, base64-encoded - a
|
|
143
|
+
# single token in the header (the branch below) can never
|
|
144
|
+
# authenticate against an API that actually checks
|
|
145
|
+
# \`Authorization: Basic base64(user:pass)\`. The password may be
|
|
146
|
+
# empty (RFC 7617): Lob, for one, documents the key as the user with
|
|
147
|
+
# a blank password (\`curl -u key:\`).
|
|
146
148
|
if S.getpath(options, "auth.basic") == true do
|
|
147
149
|
secret = S.getprop(options, @option_secret, @not_found)
|
|
148
150
|
no_apikey = not is_binary(apikey) or apikey == @not_found or apikey == ""
|
|
149
151
|
no_secret = not is_binary(secret) or secret == @not_found or secret == ""
|
|
150
152
|
|
|
151
|
-
if no_apikey
|
|
153
|
+
if no_apikey do
|
|
152
154
|
S.delprop(headers, @cred_name)
|
|
153
155
|
else
|
|
154
156
|
ap = S.getpath(options, "auth.prefix")
|
|
155
157
|
auth_prefix = if is_binary(ap), do: ap, else: ""
|
|
156
|
-
b64 = Base.encode64(apikey <> ":" <> secret)
|
|
158
|
+
b64 = Base.encode64(apikey <> ":" <> if(no_secret, do: "", else: secret))
|
|
157
159
|
hv = if auth_prefix != "", do: auth_prefix <> " " <> b64, else: b64
|
|
158
160
|
S.setprop(headers, @cred_name, hv)
|
|
159
161
|
end
|
|
@@ -128,25 +128,23 @@ ${cookieHelper(spec.where)}func prepareAuthUtil(ctx *core.Context) (*core.Spec,
|
|
|
128
128
|
`
|
|
129
129
|
|
|
130
130
|
const basicBlock = !withBasic ? '' : `
|
|
131
|
-
// True HTTP Basic Auth
|
|
131
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
132
132
|
// token in the header (the branch below) can never authenticate against
|
|
133
133
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
134
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
135
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
134
136
|
if basicAuth, _ := vs.GetPath(options, []any{"auth", "basic"}).(bool); basicAuth {
|
|
135
137
|
secret := vs.GetProp(options, optionSecret, notFound)
|
|
136
138
|
|
|
137
|
-
|
|
138
|
-
if
|
|
139
|
-
|
|
140
|
-
} else if secretStr, ok := secret.(string); ok &&
|
|
141
|
-
(secretStr == notFound || secretStr == "") {
|
|
142
|
-
noSecret = true
|
|
139
|
+
secretVal, _ := secret.(string)
|
|
140
|
+
if secretVal == notFound {
|
|
141
|
+
secretVal = ""
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
if skip
|
|
144
|
+
if skip {
|
|
146
145
|
${clear(spec.where)}
|
|
147
146
|
} else {
|
|
148
147
|
apikeyVal, _ := apikey.(string)
|
|
149
|
-
secretVal, _ := secret.(string)
|
|
150
148
|
b64 := base64.StdEncoding.EncodeToString([]byte(apikeyVal + ":" + secretVal))
|
|
151
149
|
|
|
152
150
|
basicPrefix := ""
|
|
@@ -100,9 +100,11 @@ final class PrepareAuth {
|
|
|
100
100
|
].join('\n')
|
|
101
101
|
|
|
102
102
|
const basicBlock = basicBranch ? `
|
|
103
|
-
// True HTTP Basic Auth
|
|
103
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
104
104
|
// token in the header (the branch below) can never authenticate against
|
|
105
105
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
106
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
107
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
106
108
|
if (Boolean.TRUE.equals(Struct.getpath(options, List.of("auth", "basic")))) {
|
|
107
109
|
Object secret = Struct.getprop(options, OPTION_SECRET, NOT_FOUND);
|
|
108
110
|
boolean noApikey = !(apikey instanceof String)
|
|
@@ -110,7 +112,7 @@ final class PrepareAuth {
|
|
|
110
112
|
boolean noSecret = !(secret instanceof String)
|
|
111
113
|
|| NOT_FOUND.equals(secret) || "".equals(secret);
|
|
112
114
|
|
|
113
|
-
if (noApikey
|
|
115
|
+
if (noApikey) {
|
|
114
116
|
headers.remove(CRED_NAME);
|
|
115
117
|
}
|
|
116
118
|
else {
|
|
@@ -120,7 +122,7 @@ final class PrepareAuth {
|
|
|
120
122
|
basicPrefix = (String) bp;
|
|
121
123
|
}
|
|
122
124
|
String b64 = Base64.getEncoder().encodeToString(
|
|
123
|
-
((String) apikey + ":" + (String) secret).getBytes(StandardCharsets.UTF_8));
|
|
125
|
+
((String) apikey + ":" + (noSecret ? "" : (String) secret)).getBytes(StandardCharsets.UTF_8));
|
|
124
126
|
if ("".equals(basicPrefix)) {
|
|
125
127
|
headers.put(CRED_NAME, b64);
|
|
126
128
|
}
|
|
@@ -104,19 +104,21 @@ ${cookieHelper(spec.where)}
|
|
|
104
104
|
// query parameter or a cookie, so the branch is emitted only where it
|
|
105
105
|
// can mean something.
|
|
106
106
|
const basicBlock = (spec.basic && 'header' === spec.where) ? `
|
|
107
|
-
// True HTTP Basic Auth
|
|
107
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
108
108
|
// token in the header (the branch below) can never authenticate against
|
|
109
109
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
110
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
111
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
110
112
|
if (true === options.auth.basic) {
|
|
111
113
|
const secret = getprop(options, OPTION_secret, NOTFOUND)
|
|
112
114
|
const noApikey = NOTFOUND === apikey || null == apikey || '' === apikey
|
|
113
|
-
const
|
|
115
|
+
const pass = NOTFOUND === secret || null == secret ? '' : secret
|
|
114
116
|
|
|
115
|
-
if (noApikey
|
|
117
|
+
if (noApikey) {
|
|
116
118
|
delprop(headers, CRED_name)
|
|
117
119
|
}
|
|
118
120
|
else {
|
|
119
|
-
const b64 = Buffer.from(apikey + ':' +
|
|
121
|
+
const b64 = Buffer.from(apikey + ':' + pass).toString('base64')
|
|
120
122
|
setprop(headers, CRED_name,
|
|
121
123
|
options.auth.prefix ? options.auth.prefix + ' ' + b64 : b64)
|
|
122
124
|
}
|
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, isPublished, repoInfo } from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
const ReadmeInstall = cmp(function ReadmeInstall(props: any) {
|
|
6
|
-
const { target } = props
|
|
6
|
+
const { target, ctx$ } = props
|
|
7
|
+
const { model } = ctx$
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
if (isPublished(model, target.name)) {
|
|
10
|
+
Content('```js')
|
|
11
|
+
Content(`
|
|
10
12
|
npm install ${target.module.name}
|
|
11
13
|
`)
|
|
12
|
-
|
|
14
|
+
Content('```')
|
|
15
|
+
return
|
|
16
|
+
}
|
|
13
17
|
|
|
18
|
+
// Publish pending, as in the ts target: a tag may not exist, so a clone is
|
|
19
|
+
// always offered. The js target needs no build.
|
|
20
|
+
const { releasesUrl, repoUrl, repo } = repoInfo(model)
|
|
21
|
+
Content(`This package is not yet published to npm. Install it from the GitHub
|
|
22
|
+
release tag (\`${target.name}/vX.Y.Z\`, see [Releases](${releasesUrl})), or from a
|
|
23
|
+
clone:
|
|
24
|
+
|
|
25
|
+
\`\`\`bash
|
|
26
|
+
git clone ${repoUrl}
|
|
27
|
+
npm install ./${repo}/${target.name}
|
|
28
|
+
\`\`\`
|
|
29
|
+
|
|
30
|
+
`)
|
|
14
31
|
})
|
|
15
32
|
|
|
16
33
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cmp, File, Content, definitionPlan } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// Every operation checked against the API definition, offline, in the SDK's
|
|
5
|
+
// own suite: see test/definition-runner. Mirrors the ts component.
|
|
6
|
+
const TestDefinition = cmp(function TestDefinition(props: any) {
|
|
7
|
+
const plan = definitionPlan(props.ctx$)
|
|
8
|
+
if (0 === plan.length) return
|
|
9
|
+
|
|
10
|
+
File({ name: 'definition.test.js' }, () => Content(`const { describe, test } = require('node:test')
|
|
11
|
+
const { SDK } = require('..')
|
|
12
|
+
const { runDefinitionPoint } = require('./definition-runner')
|
|
13
|
+
const { isControlSkipped } = require('./utility')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// Generated from the API definition, not from the model this SDK was built
|
|
17
|
+
// from: the route, the declared query parameters, the credential the security
|
|
18
|
+
// scheme names, and the definition's own response example.
|
|
19
|
+
const PLAN = ${JSON.stringify(plan, null, 2)}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
describe('definition', () => {
|
|
23
|
+
for (const point of PLAN) {
|
|
24
|
+
test(point.entity + '.' + point.op + ' ' + point.method + ' ' + point.path, async (t) => {
|
|
25
|
+
const control = isControlSkipped('entityOp', point.entity + '.' + point.op, 'definition')
|
|
26
|
+
if (control.skip) {
|
|
27
|
+
t.skip(control.reason || 'skipped via sdk-test-control.json')
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
await runDefinitionPoint(SDK, point)
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
`))
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
TestDefinition
|
|
40
|
+
}
|
|
@@ -8,6 +8,7 @@ import { cmp, each, Folder, entityCollection,
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
import { TestLive } from './TestLive_js'
|
|
11
|
+
import { TestDefinition } from './TestDefinition_js'
|
|
11
12
|
import { TestDirect } from './TestDirect_js'
|
|
12
13
|
import { TestEntity } from './TestEntity_js'
|
|
13
14
|
|
|
@@ -21,6 +22,7 @@ const Test = cmp(function Test(props: any) {
|
|
|
21
22
|
// Write-once: a project's edited control file survives regeneration.
|
|
22
23
|
TestControl({ target, dir: 'test' })
|
|
23
24
|
TestLive({ target })
|
|
25
|
+
TestDefinition({ target })
|
|
24
26
|
|
|
25
27
|
Folder({ name: 'entity' }, () => {
|
|
26
28
|
const entity = each(entityCollection(model))
|
|
@@ -156,9 +156,11 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
156
156
|
if (!spec.basic) return ''
|
|
157
157
|
|
|
158
158
|
return `
|
|
159
|
-
// True HTTP Basic Auth
|
|
159
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
160
160
|
// token in the header (the branch below) can never authenticate against
|
|
161
161
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
162
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
163
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
162
164
|
val basicOpt = Struct.getpath(options, listOf("auth", "basic"))
|
|
163
165
|
if (basicOpt is Boolean && basicOpt) {
|
|
164
166
|
val secret = Struct.getprop(options, OPTION_SECRET, NOT_FOUND)
|
|
@@ -167,7 +169,7 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
167
169
|
val noSecret = secret == null ||
|
|
168
170
|
(secret is String && (NOT_FOUND == secret || "" == secret))
|
|
169
171
|
|
|
170
|
-
if (noApikey
|
|
172
|
+
if (noApikey) {
|
|
171
173
|
headers.remove(HEADER_AUTH)
|
|
172
174
|
} else {
|
|
173
175
|
var basicPrefix = ""
|
|
@@ -176,7 +178,7 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
176
178
|
basicPrefix = bp
|
|
177
179
|
}
|
|
178
180
|
val b64 = Base64.getEncoder().encodeToString(
|
|
179
|
-
(apikey.toString() + ":" + secret.toString()).toByteArray(Charsets.UTF_8))
|
|
181
|
+
(apikey.toString() + ":" + (if (noSecret) "" else secret.toString())).toByteArray(Charsets.UTF_8))
|
|
180
182
|
if ("" == basicPrefix) {
|
|
181
183
|
headers[HEADER_AUTH] = b64
|
|
182
184
|
} else {
|
|
@@ -189,15 +189,19 @@ function place(where: string): string {
|
|
|
189
189
|
|
|
190
190
|
|
|
191
191
|
const BASIC = `
|
|
192
|
-
-- True HTTP Basic Auth
|
|
192
|
+
-- True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
193
193
|
-- token in the header (the branch below) can never authenticate against
|
|
194
194
|
-- an API that actually checks "Authorization: Basic base64(user:pass)".
|
|
195
|
+
-- The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
196
|
+
-- the user with a blank password ("curl -u key:").
|
|
195
197
|
if vs.getpath(options, "auth.basic") == true then
|
|
196
198
|
local secret = vs.getprop(options, OPTION_SECRET, NOT_FOUND)
|
|
199
|
+
if secret == nil or secret == NOT_FOUND then
|
|
200
|
+
secret = ""
|
|
201
|
+
end
|
|
197
202
|
|
|
198
|
-
if apikey == nil
|
|
203
|
+
if apikey == nil
|
|
199
204
|
or (type(apikey) == "string" and (apikey == NOT_FOUND or apikey == ""))
|
|
200
|
-
or (type(secret) == "string" and (secret == NOT_FOUND or secret == ""))
|
|
201
205
|
then
|
|
202
206
|
headers[HEADER_AUTH] = nil
|
|
203
207
|
else
|
|
@@ -255,20 +255,22 @@ let prepare_auth_util (ctx : ctx) : (spec option * sdk_error option) =
|
|
|
255
255
|
|
|
256
256
|
|
|
257
257
|
const BASIC = ` if (match getpath_s options "auth.basic" with Bool b -> b | _ -> false) then begin
|
|
258
|
-
(* True HTTP Basic Auth
|
|
259
|
-
* single token in the header (the branch below) can never
|
|
258
|
+
(* True HTTP Basic Auth joins the two credentials, base64-encoded -
|
|
259
|
+
* a single token in the header (the branch below) can never
|
|
260
260
|
* authenticate against an API that actually checks
|
|
261
|
-
* \`Authorization: Basic base64(user:pass)\`.
|
|
261
|
+
* \`Authorization: Basic base64(user:pass)\`. The password may be
|
|
262
|
+
* empty (RFC 7617): Lob, for one, documents the key as the user
|
|
263
|
+
* with a blank password (\`curl -u key:\`). *)
|
|
262
264
|
let secret = getprop ~alt:(Str not_found) options (Str option_secret) in
|
|
263
265
|
let no_secret =
|
|
264
266
|
(match secret with Str s -> s = not_found | _ -> false)
|
|
265
267
|
|| is_noval secret || secret = Str "" in
|
|
266
|
-
if no_apikey
|
|
268
|
+
if no_apikey then
|
|
267
269
|
ignore (delprop headers (Str cred_name))
|
|
268
270
|
else begin
|
|
269
271
|
let auth_prefix = match getpath_s options "auth.prefix" with Str s -> s | _ -> "" in
|
|
270
272
|
let apikey_val = match apikey with Str s -> s | _ -> "" in
|
|
271
|
-
let secret_val = match secret with Str s -> s | _ -> "" in
|
|
273
|
+
let secret_val = if no_secret then "" else match secret with Str s -> s | _ -> "" in
|
|
272
274
|
let joined = base64_encode (apikey_val ^ ":" ^ secret_val) in
|
|
273
275
|
setp headers cred_name
|
|
274
276
|
(Str (if auth_prefix <> "" then auth_prefix ^ " " ^ joined else joined))
|
|
@@ -266,9 +266,11 @@ function basicBlock(spec: AuthSpec, wantBasic: boolean): string {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
return `
|
|
269
|
-
# True HTTP Basic Auth
|
|
269
|
+
# True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
270
270
|
# token in the header (the branch below) can never authenticate against
|
|
271
271
|
# an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
272
|
+
# The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
273
|
+
# the user with a blank password (\`curl -u key:\`).
|
|
272
274
|
if (${spec.Name}Helpers::is_true(${spec.Name}Helpers::gpath($options, 'auth.basic'))) {
|
|
273
275
|
my $secret = Voxgig::Struct::getprop($options, $OPTION_SECRET, $NOT_FOUND);
|
|
274
276
|
|
|
@@ -279,7 +281,7 @@ function basicBlock(spec: AuthSpec, wantBasic: boolean): string {
|
|
|
279
281
|
|| Voxgig::Struct::is_jnull($secret)
|
|
280
282
|
|| (!ref $secret && ($secret eq $NOT_FOUND || $secret eq ''));
|
|
281
283
|
|
|
282
|
-
if ($no_apikey
|
|
284
|
+
if ($no_apikey) {
|
|
283
285
|
delete $headers->{$CRED_NAME};
|
|
284
286
|
}
|
|
285
287
|
else {
|
|
@@ -287,7 +289,8 @@ function basicBlock(spec: AuthSpec, wantBasic: boolean): string {
|
|
|
287
289
|
$auth_prefix = '' unless defined $auth_prefix && !ref $auth_prefix;
|
|
288
290
|
# '' as the eol: encode_base64 wraps at 76 columns by default, and a
|
|
289
291
|
# newline inside a header value is not a header value.
|
|
290
|
-
my $
|
|
292
|
+
my $pass = $no_secret ? '' : $secret;
|
|
293
|
+
my $b64 = MIME::Base64::encode_base64("$apikey:$pass", '');
|
|
291
294
|
$headers->{$CRED_NAME} =
|
|
292
295
|
('' eq $auth_prefix) ? $b64 : "$auth_prefix $b64";
|
|
293
296
|
}
|
|
@@ -201,16 +201,18 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
return `
|
|
204
|
-
// True HTTP Basic Auth
|
|
204
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a
|
|
205
205
|
// single token in the header (the branch below) can never
|
|
206
206
|
// authenticate against an API that actually checks
|
|
207
|
-
// \`Authorization: Basic base64(user:pass)\`.
|
|
207
|
+
// \`Authorization: Basic base64(user:pass)\`. The password may be
|
|
208
|
+
// empty (RFC 7617): Lob, for one, documents the key as the user with
|
|
209
|
+
// a blank password (\`curl -u key:\`).
|
|
208
210
|
if (true === (\\Voxgig\\Struct\\Struct::getpath($options, 'auth.basic') ?? false)) {
|
|
209
211
|
$secret = \\Voxgig\\Struct\\Struct::getprop($options, self::OPTION_SECRET, self::NOT_FOUND);
|
|
210
212
|
$apikey_val = is_string($apikey) && $apikey !== self::NOT_FOUND ? $apikey : '';
|
|
211
213
|
$secret_val = is_string($secret) && $secret !== self::NOT_FOUND ? $secret : '';
|
|
212
214
|
|
|
213
|
-
if ($apikey_val === ''
|
|
215
|
+
if ($apikey_val === '') {
|
|
214
216
|
unset($headers[self::HEADER_AUTH]);
|
|
215
217
|
} else {
|
|
216
218
|
$auth_prefix = \\Voxgig\\Struct\\Struct::getpath($options, 'auth.prefix') ?? '';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content, installCommand, isPublished, repoInfo } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, installCommand, isPublished, packageName, repoInfo } from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
const ReadmeInstall = cmp(function ReadmeInstall(props: any) {
|
|
@@ -15,12 +15,18 @@ ${installCommand(model, target.name)}
|
|
|
15
15
|
return
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// Publish pending: not yet on Packagist. Install from the git release tag
|
|
19
|
-
|
|
18
|
+
// Publish pending: not yet on Packagist. Install from the git release tag,
|
|
19
|
+
// or from a clone as a Composer path repository, since a tag may not exist.
|
|
20
|
+
const { releasesUrl, repoUrl, repo } = repoInfo(model)
|
|
20
21
|
Content(`This package is not yet published to Packagist. Install it from the
|
|
21
|
-
GitHub release tag (\`${target.name}/vX.Y.Z
|
|
22
|
+
GitHub release tag (\`${target.name}/vX.Y.Z\`, see [Releases](${releasesUrl})), or
|
|
23
|
+
from a clone as a Composer path repository:
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
\`\`\`bash
|
|
26
|
+
git clone ${repoUrl}
|
|
27
|
+
composer config repositories.${repo} path ./${repo}/${target.name}
|
|
28
|
+
composer require ${packageName(model, target.name)}:@dev
|
|
29
|
+
\`\`\`
|
|
24
30
|
|
|
25
31
|
`)
|
|
26
32
|
})
|
|
@@ -140,9 +140,11 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
140
140
|
if (!spec.basic) return ''
|
|
141
141
|
|
|
142
142
|
return `
|
|
143
|
-
# True HTTP Basic Auth
|
|
143
|
+
# True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
144
144
|
# token in the header (the branch below) can never authenticate against
|
|
145
145
|
# an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
146
|
+
# The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
147
|
+
# the user with a blank password (\`curl -u key:\`).
|
|
146
148
|
if vs.getpath(options, "auth.basic") is True:
|
|
147
149
|
secret = vs.getprop(options, OPTION_SECRET, NOT_FOUND)
|
|
148
150
|
no_apikey = (
|
|
@@ -156,7 +158,7 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
156
158
|
or secret == ""
|
|
157
159
|
)
|
|
158
160
|
|
|
159
|
-
if no_apikey
|
|
161
|
+
if no_apikey:
|
|
160
162
|
headers.pop(HEADER_AUTH, None)
|
|
161
163
|
else:
|
|
162
164
|
auth_prefix = ""
|
|
@@ -164,7 +166,7 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
164
166
|
if isinstance(ap, str):
|
|
165
167
|
auth_prefix = ap
|
|
166
168
|
b64 = base64.b64encode(
|
|
167
|
-
(str(apikey) + ":" + str(secret)).encode("utf-8")
|
|
169
|
+
(str(apikey) + ":" + ("" if no_secret else str(secret))).encode("utf-8")
|
|
168
170
|
).decode("ascii")
|
|
169
171
|
headers[HEADER_AUTH] = (
|
|
170
172
|
auth_prefix + " " + b64 if auth_prefix else b64
|
|
@@ -124,21 +124,23 @@ end
|
|
|
124
124
|
`
|
|
125
125
|
|
|
126
126
|
const basicBlock = !basicHere ? '' : `
|
|
127
|
-
# True HTTP Basic Auth
|
|
127
|
+
# True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
128
128
|
# token in the header (the branch below) can never authenticate against
|
|
129
129
|
# an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
130
|
+
# The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
131
|
+
# the user with a blank password (\`curl -u key:\`).
|
|
130
132
|
if VoxgigStruct.getpath(options, "auth.basic") == true
|
|
131
133
|
secret = VoxgigStruct.getprop(options, OPTION_SECRET, NOT_FOUND)
|
|
132
134
|
no_apikey = apikey.nil? || !apikey.is_a?(String) || apikey == NOT_FOUND || apikey == ""
|
|
133
135
|
no_secret = secret.nil? || !secret.is_a?(String) || secret == NOT_FOUND || secret == ""
|
|
134
136
|
|
|
135
|
-
if no_apikey
|
|
137
|
+
if no_apikey
|
|
136
138
|
headers.delete(HEADER_AUTH)
|
|
137
139
|
else
|
|
138
140
|
auth_prefix = VoxgigStruct.getpath(options, "auth.prefix") || ""
|
|
139
141
|
# \`pack("m0")\` rather than \`Base64.strict_encode64\`: base64 left
|
|
140
142
|
# Ruby's default gems in 3.4, and pack is core.
|
|
141
|
-
b64 = ["#{apikey}:#{secret}"].pack("m0")
|
|
143
|
+
b64 = ["#{apikey}:#{no_secret ? "" : secret}"].pack("m0")
|
|
142
144
|
headers[HEADER_AUTH] =
|
|
143
145
|
auth_prefix.empty? ? b64 : "#{auth_prefix} #{b64}"
|
|
144
146
|
end
|
|
@@ -27,12 +27,22 @@ bundle install
|
|
|
27
27
|
return
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// Publish pending: not yet on RubyGems. Install from the git release tag
|
|
31
|
-
|
|
30
|
+
// Publish pending: not yet on RubyGems. Install from the git release tag,
|
|
31
|
+
// or from a clone through Bundler, since a tag may not exist.
|
|
32
|
+
const { releasesUrl, repoUrl, repo } = repoInfo(model)
|
|
32
33
|
Content(`This package is not yet published to RubyGems. Install it from the
|
|
33
|
-
GitHub release tag (\`${target.name}/vX.Y.Z
|
|
34
|
+
GitHub release tag (\`${target.name}/vX.Y.Z\`, see [Releases](${releasesUrl})), or
|
|
35
|
+
from a clone:
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
\`\`\`bash
|
|
38
|
+
git clone ${repoUrl}
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
Then add it to your \`Gemfile\` by path, and run \`bundle install\`:
|
|
42
|
+
|
|
43
|
+
\`\`\`ruby
|
|
44
|
+
gem "${packageName(model, target.name)}", path: "./${repo}/${target.name}"
|
|
45
|
+
\`\`\`
|
|
36
46
|
|
|
37
47
|
`)
|
|
38
48
|
})
|
|
@@ -136,9 +136,11 @@ pub fn prepare_auth_util(ctx: &Rc<Context>) -> Result<Rc<RefCell<Spec>>, ${spec.
|
|
|
136
136
|
`
|
|
137
137
|
|
|
138
138
|
const basicBlock = !withBasic ? '' : `
|
|
139
|
-
// True HTTP Basic Auth
|
|
139
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
140
140
|
// token in the header (the branch below) can never authenticate against
|
|
141
141
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
142
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
143
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
142
144
|
if let Value::Bool(true) = getpath(&["auth", "basic"], &options) {
|
|
143
145
|
let secret = vs::get_prop(&options, &Value::str(OPTION_SECRET), Value::str(NOT_FOUND));
|
|
144
146
|
|
|
@@ -148,7 +150,7 @@ pub fn prepare_auth_util(ctx: &Rc<Context>) -> Result<Rc<RefCell<Spec>>, ${spec.
|
|
|
148
150
|
_ => false,
|
|
149
151
|
};
|
|
150
152
|
|
|
151
|
-
if skip
|
|
153
|
+
if skip {
|
|
152
154
|
vs::del_prop(headers, &Value::str(CRED_NAME));
|
|
153
155
|
} else {
|
|
154
156
|
let apikey_val = match &apikey {
|
|
@@ -156,7 +158,7 @@ pub fn prepare_auth_util(ctx: &Rc<Context>) -> Result<Rc<RefCell<Spec>>, ${spec.
|
|
|
156
158
|
_ => String::new(),
|
|
157
159
|
};
|
|
158
160
|
let secret_val = match &secret {
|
|
159
|
-
Value::Str(s) => s.clone(),
|
|
161
|
+
Value::Str(s) if !no_secret => s.clone(),
|
|
160
162
|
_ => String::new(),
|
|
161
163
|
};
|
|
162
164
|
let b64 = base64_encode(format!("{}:{}", apikey_val, secret_val).as_bytes());
|
|
@@ -146,22 +146,24 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
146
146
|
if (!spec.basic) return ''
|
|
147
147
|
|
|
148
148
|
return `
|
|
149
|
-
// True HTTP Basic Auth
|
|
149
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
150
150
|
// token in the header (the branch below) can never authenticate against
|
|
151
151
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
152
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
153
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
152
154
|
if (java.lang.Boolean.TRUE == Struct.getpath(options, java.util.List.of("auth", "basic"))) {
|
|
153
155
|
val secret = Struct.getprop(options, OPTION_SECRET, NOT_FOUND)
|
|
154
156
|
val noApikey = apikey == null || (apikey match { case s: String => NOT_FOUND == s || "" == s; case _ => false })
|
|
155
157
|
val noSecret = secret == null || (secret match { case s: String => NOT_FOUND == s || "" == s; case _ => false })
|
|
156
158
|
|
|
157
|
-
if (noApikey
|
|
159
|
+
if (noApikey) {
|
|
158
160
|
headers.remove(CRED_NAME)
|
|
159
161
|
} else {
|
|
160
162
|
var basicPrefix = ""
|
|
161
163
|
Struct.getpath(options, java.util.List.of("auth", "prefix")) match { case s: String => basicPrefix = s; case _ => }
|
|
162
164
|
val b64 = Base64.getEncoder.encodeToString(
|
|
163
165
|
((apikey match { case s: String => s; case _ => "" }) + ":" +
|
|
164
|
-
(secret match { case s: String => s; case _ => "" })).getBytes(StandardCharsets.UTF_8))
|
|
166
|
+
(if (noSecret) "" else secret match { case s: String => s; case _ => "" })).getBytes(StandardCharsets.UTF_8))
|
|
165
167
|
if ("" == basicPrefix) headers.put(CRED_NAME, b64)
|
|
166
168
|
else headers.put(CRED_NAME, basicPrefix + " " + b64)
|
|
167
169
|
}
|