vestauth 0.5.3 → 0.6.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 +6 -0
- package/package.json +1 -1
- package/src/cli/actions/agent/headers.js +1 -1
- package/src/cli/actions/agent/init.js +15 -9
- package/src/cli/actions/primitives/headers.js +17 -12
- package/src/cli/actions/primitives/keypair.js +2 -4
- package/src/cli/actions/primitives/verify.js +26 -15
- package/src/cli/actions/provider/verify.js +23 -13
- package/src/cli/commands/agent.js +8 -6
- package/src/cli/commands/primitives.js +12 -9
- package/src/cli/commands/provider.js +4 -3
- package/src/lib/api/postRegister.js +1 -1
- package/src/lib/helpers/agentHeaders.js +4 -4
- package/src/lib/helpers/catchAndLog.js +16 -0
- package/src/lib/helpers/errors.js +34 -1
- package/src/lib/helpers/headers.js +17 -15
- package/src/lib/helpers/identity.js +3 -3
- package/src/lib/helpers/parseSignatureAgentHeader.js +18 -0
- package/src/lib/helpers/providerVerify.js +29 -3
- package/src/lib/helpers/publicKeyObject.js +7 -0
- package/src/lib/helpers/signatureParams.js +1 -1
- package/src/lib/helpers/verify.js +10 -8
- package/src/lib/helpers/verifyWebBotAuth.js +1 -1
- package/src/lib/helpers/edPublicKeyObject.js +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
4
4
|
|
|
5
5
|
[Unreleased](https://github.com/vestauth/vestauth/compare/v0.5.3...main)
|
|
6
6
|
|
|
7
|
+
## [0.6.0](https://github.com/vestauth/vestauth/compare/v0.5.3...v0.6.0) (2026-02-03)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Add `provider verify` command ([#8](https://github.com/vestauth/vestauth/pull/8))
|
|
12
|
+
|
|
7
13
|
## [0.5.3](https://github.com/vestauth/vestauth/compare/v0.5.2...v0.5.3) (2026-02-03)
|
|
8
14
|
|
|
9
15
|
### Changed
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ async function headers (httpMethod, uri) {
|
|
|
9
9
|
const options = this.opts()
|
|
10
10
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
11
11
|
|
|
12
|
-
const output = await agent.headers(httpMethod, uri, options.
|
|
12
|
+
const output = await agent.headers(httpMethod, uri, options.id, options.privateKey, options.tag, options.nonce)
|
|
13
13
|
|
|
14
14
|
let space = 0
|
|
15
15
|
if (options.prettyPrint) {
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
const { logger } = require('./../../../shared/logger')
|
|
2
|
+
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
|
2
3
|
|
|
3
4
|
const agent = require('./../../../lib/agent')
|
|
4
5
|
|
|
5
6
|
async function init () {
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
try {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
const output = await agent.init()
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (output.isNew) {
|
|
14
|
+
logger.success(`✔ agent created (${output.path}/AGENT_ID=${output.AGENT_ID})`)
|
|
15
|
+
} else {
|
|
16
|
+
logger.info(`• agent exists (${output.path}/AGENT_ID=${output.AGENT_ID})`)
|
|
17
|
+
}
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
logger.help('⮕ next run: [vestauth agent curl https://api.vestauth.com/whoami]')
|
|
20
|
+
} catch (error) {
|
|
21
|
+
catchAndLog(error)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
module.exports = init
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
const { logger } = require('./../../../shared/logger')
|
|
2
|
+
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
|
2
3
|
|
|
3
4
|
const primitives = require('./../../../lib/primitives')
|
|
4
5
|
|
|
5
|
-
async function headers (httpMethod, uri
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
async function headers (httpMethod, uri) {
|
|
7
|
+
try {
|
|
8
|
+
logger.debug(`httpMethod: ${httpMethod}`)
|
|
9
|
+
logger.debug(`uri: ${uri}`)
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const options = this.opts()
|
|
12
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
const output = await primitives.headers(httpMethod, uri, options.id, options.privateKey, options.tag, options.nonce)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
let space = 0
|
|
17
|
+
if (options.prettyPrint) {
|
|
18
|
+
space = 2
|
|
19
|
+
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
console.log(JSON.stringify(output, null, space))
|
|
22
|
+
} catch (error) {
|
|
23
|
+
catchAndLog(error)
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
module.exports = headers
|
|
@@ -2,13 +2,11 @@ const { logger } = require('./../../../shared/logger')
|
|
|
2
2
|
|
|
3
3
|
const primitives = require('./../../../lib/primitives')
|
|
4
4
|
|
|
5
|
-
function keypair (
|
|
6
|
-
logger.debug(`existingPrivateKey: ${existingPrivateKey}`)
|
|
7
|
-
|
|
5
|
+
function keypair () {
|
|
8
6
|
const options = this.opts()
|
|
9
7
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
10
8
|
|
|
11
|
-
const kp = primitives.keypair(
|
|
9
|
+
const kp = primitives.keypair(options.privateKey, options.prefix)
|
|
12
10
|
|
|
13
11
|
const output = {
|
|
14
12
|
public_key: kp.publicKey,
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
const { logger } = require('./../../../shared/logger')
|
|
2
|
+
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
|
2
3
|
|
|
3
4
|
const primitives = require('./../../../lib/primitives')
|
|
4
5
|
|
|
5
|
-
async function verify (httpMethod, uri
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
logger.debug(`signatureInput: ${signatureInput}`)
|
|
10
|
-
logger.debug(`publicKey: ${publicKey}`)
|
|
6
|
+
async function verify (httpMethod, uri) {
|
|
7
|
+
try {
|
|
8
|
+
logger.debug(`httpMethod: ${httpMethod}`)
|
|
9
|
+
logger.debug(`uri: ${uri}`)
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const options = this.opts()
|
|
12
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const headers = {
|
|
15
|
+
Signature: options.signature,
|
|
16
|
+
'Signature-Input': options.signatureInput,
|
|
17
|
+
'Signature-Agent': options.signatureAgent
|
|
18
|
+
}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const publicJwk = JSON.parse(options.publicKey || {})
|
|
21
|
+
|
|
22
|
+
const output = await primitives.verify(httpMethod, uri, headers, publicJwk)
|
|
23
|
+
// const output = await primitive.verifyWebBotAuth(httpMethod, uri, signature, signatureInput, JSON.parse(publicKey))
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
let space = 0
|
|
26
|
+
if (options.prettyPrint) {
|
|
27
|
+
space = 2
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(JSON.stringify(output, null, space))
|
|
31
|
+
} catch (error) {
|
|
32
|
+
catchAndLog(error)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
module.exports = verify
|
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
const { logger } = require('./../../../shared/logger')
|
|
2
|
+
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
|
2
3
|
|
|
3
4
|
const provider = require('./../../../lib/provider')
|
|
4
5
|
|
|
5
|
-
async function verify (httpMethod, uri
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
logger.debug(`signatureInputHeader: ${signatureInputHeader}`)
|
|
6
|
+
async function verify (httpMethod, uri) {
|
|
7
|
+
try {
|
|
8
|
+
logger.debug(`httpMethod: ${httpMethod}`)
|
|
9
|
+
logger.debug(`uri: ${uri}`)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const options = this.opts()
|
|
12
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const headers = {
|
|
15
|
+
Signature: options.signature,
|
|
16
|
+
'Signature-Input': options.signatureInput,
|
|
17
|
+
'Signature-Agent': options.signatureAgent
|
|
18
|
+
}
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
space =
|
|
19
|
-
|
|
20
|
+
const output = await provider.verify(httpMethod, uri, headers)
|
|
21
|
+
|
|
22
|
+
let space = 0
|
|
23
|
+
if (options.prettyPrint) {
|
|
24
|
+
space = 2
|
|
25
|
+
}
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
console.log(JSON.stringify(output, null, space))
|
|
28
|
+
} catch (error) {
|
|
29
|
+
catchAndLog(error)
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
module.exports = verify
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { Command } = require('commander')
|
|
2
|
+
const env = require('./../../lib/helpers/env')
|
|
2
3
|
|
|
3
4
|
const agent = new Command('agent')
|
|
4
5
|
|
|
@@ -11,7 +12,7 @@ agent
|
|
|
11
12
|
const initAction = require('./../actions/agent/init')
|
|
12
13
|
agent.command('init')
|
|
13
14
|
.description('create agent')
|
|
14
|
-
.option('
|
|
15
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
15
16
|
.action(initAction)
|
|
16
17
|
|
|
17
18
|
// vestauth agent curl
|
|
@@ -19,9 +20,9 @@ const curlAction = require('./../actions/agent/curl')
|
|
|
19
20
|
agent.command('curl')
|
|
20
21
|
.description('run curl as agent')
|
|
21
22
|
.allowUnknownOption()
|
|
22
|
-
.option('--tag <tag>', 'web-bot-auth (default) | web-bot-auth', '
|
|
23
|
+
.option('--tag <tag>', 'web-bot-auth (default) | web-bot-auth', 'web-bot-auth')
|
|
23
24
|
.option('--nonce <nonce>', 'null (default)')
|
|
24
|
-
.option('
|
|
25
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
25
26
|
.action(curlAction)
|
|
26
27
|
|
|
27
28
|
// vestauth agent headers
|
|
@@ -30,10 +31,11 @@ agent.command('headers')
|
|
|
30
31
|
.description('generate headers as agent')
|
|
31
32
|
.argument('<httpMethod>', 'GET (default)')
|
|
32
33
|
.argument('<uri>', '')
|
|
33
|
-
.option('--
|
|
34
|
+
.option('--id <id>', 'id (string)', env('AGENT_ID'))
|
|
35
|
+
.option('--privateKey <privateKey>', 'AGENT_PUBLIC_KEY (default)', env('AGENT_PRIVATE_KEY'))
|
|
36
|
+
.option('--tag <tag>', 'web-bot-auth (default) | web-bot-auth', 'web-bot-auth')
|
|
34
37
|
.option('--nonce <nonce>', 'null (default)')
|
|
35
|
-
.option('--
|
|
36
|
-
.option('-pp, --pretty-print', 'pretty print output')
|
|
38
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
37
39
|
.action(headersAction)
|
|
38
40
|
|
|
39
41
|
module.exports = agent
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { Command } = require('commander')
|
|
2
|
+
const env = require('./../../lib/helpers/env')
|
|
2
3
|
|
|
3
4
|
const primitives = new Command('primitives')
|
|
4
5
|
|
|
@@ -10,9 +11,9 @@ primitives
|
|
|
10
11
|
const keypairAction = require('./../actions/primitives/keypair')
|
|
11
12
|
primitives.command('keypair')
|
|
12
13
|
.description('generate public/private keypair')
|
|
13
|
-
.
|
|
14
|
+
.option('--private-key <privateKey>', 'pre-existing private key')
|
|
14
15
|
.option('--prefix <type>', 'agent (default) | provider | none', 'agent')
|
|
15
|
-
.option('
|
|
16
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
16
17
|
.action(keypairAction)
|
|
17
18
|
|
|
18
19
|
// vestauth primitives headers
|
|
@@ -21,10 +22,11 @@ primitives.command('headers')
|
|
|
21
22
|
.description('generate signed headers')
|
|
22
23
|
.argument('<httpMethod>', 'GET (default)')
|
|
23
24
|
.argument('<uri>', '')
|
|
24
|
-
.
|
|
25
|
-
.option('--
|
|
25
|
+
.option('--id <id>', 'id (string)', env('AGENT_ID'))
|
|
26
|
+
.option('--private-key <privateKey>', 'private key (json string)', env('AGENT_PRIVATE_KEY'))
|
|
27
|
+
.option('--tag <tag>', 'web-bot-auth (default) | web-bot-auth', 'web-bot-auth')
|
|
26
28
|
.option('--nonce <nonce>', 'null (default)')
|
|
27
|
-
.option('
|
|
29
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
28
30
|
.action(headersAction)
|
|
29
31
|
|
|
30
32
|
// vestauth primitives verify
|
|
@@ -33,10 +35,11 @@ primitives.command('verify')
|
|
|
33
35
|
.description('verify signed headers')
|
|
34
36
|
.argument('<httpMethod>', 'GET (default)')
|
|
35
37
|
.argument('<uri>', '')
|
|
36
|
-
.
|
|
37
|
-
.
|
|
38
|
-
.
|
|
39
|
-
.option('-
|
|
38
|
+
.requiredOption('--signature <signature>', '')
|
|
39
|
+
.requiredOption('--signature-input <signatureInput>', '')
|
|
40
|
+
.option('--signature-agent <signatureAgent>', '')
|
|
41
|
+
.option('--public-key <publicKey>', 'public key (json string)', env('AGENT_PUBLIC_KEY'))
|
|
42
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
40
43
|
.action(verifyAction)
|
|
41
44
|
|
|
42
45
|
module.exports = primitives
|
|
@@ -12,9 +12,10 @@ provider.command('verify')
|
|
|
12
12
|
.description('verify agent')
|
|
13
13
|
.argument('<httpMethod>', 'GET (default)')
|
|
14
14
|
.argument('<uri>', '')
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
.
|
|
15
|
+
.requiredOption('--signature <signature>', '')
|
|
16
|
+
.requiredOption('--signature-input <signatureInput>', '')
|
|
17
|
+
.requiredOption('--signature-agent <signatureAgent>', '')
|
|
18
|
+
.option('--pp, --pretty-print', 'pretty print output')
|
|
18
19
|
.action(verifyAction)
|
|
19
20
|
|
|
20
21
|
module.exports = provider
|
|
@@ -13,7 +13,7 @@ class PostRegister {
|
|
|
13
13
|
const publicJwk = this.publicJwk
|
|
14
14
|
|
|
15
15
|
const httpMethod = 'POST'
|
|
16
|
-
const headers = await agentHeaders(httpMethod, url)
|
|
16
|
+
const headers = await agentHeaders(httpMethod, url, 'agent-123')
|
|
17
17
|
headers['Content-Type'] = 'application/json'
|
|
18
18
|
|
|
19
19
|
const resp = await http(url, {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
const headers = require('./headers')
|
|
2
2
|
const identity = require('./identity')
|
|
3
3
|
|
|
4
|
-
async function agentHeaders (httpMethod, uri,
|
|
4
|
+
async function agentHeaders (httpMethod, uri, id = null, privateKey = null, tag = 'web-bot-auth', nonce = null) {
|
|
5
5
|
if (!privateKey) {
|
|
6
6
|
privateKey = identity().privateKey
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
if (!
|
|
10
|
-
|
|
9
|
+
if (!id) {
|
|
10
|
+
id = identity().id
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
return await headers(httpMethod, uri,
|
|
13
|
+
return await headers(httpMethod, uri, id, privateKey, tag, nonce)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
module.exports = agentHeaders
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { logger } = require('./../../shared/logger')
|
|
2
|
+
|
|
3
|
+
function catchAndLog (error) {
|
|
4
|
+
logger.error(error.message)
|
|
5
|
+
if (error.help) {
|
|
6
|
+
logger.help(error.help)
|
|
7
|
+
}
|
|
8
|
+
if (error.debug) {
|
|
9
|
+
logger.debug(error.debug)
|
|
10
|
+
}
|
|
11
|
+
if (error.code) {
|
|
12
|
+
logger.debug(`ERROR_CODE: ${error.code}`)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = catchAndLog
|
|
@@ -3,6 +3,39 @@ class Errors {
|
|
|
3
3
|
this.message = options.message
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
missingId () {
|
|
7
|
+
const code = 'MISSING_ID'
|
|
8
|
+
const message = `[${code}] missing --id (AGENT_ID)`
|
|
9
|
+
const help = `[${code}] https://github.com/vestauth/vestauth/issues/6`
|
|
10
|
+
|
|
11
|
+
const e = new Error(message)
|
|
12
|
+
e.code = code
|
|
13
|
+
e.help = help
|
|
14
|
+
return e
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
missingPrivateKey () {
|
|
18
|
+
const code = 'MISSING_PRIVATE_KEY'
|
|
19
|
+
const message = `[${code}] missing --private-key (AGENT_PRIVATE_KEY)`
|
|
20
|
+
const help = `[${code}] https://github.com/vestauth/vestauth/issues/5`
|
|
21
|
+
|
|
22
|
+
const e = new Error(message)
|
|
23
|
+
e.code = code
|
|
24
|
+
e.help = help
|
|
25
|
+
return e
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
invalidPrivateKey () {
|
|
29
|
+
const code = 'INVALID_PRIVATE_KEY'
|
|
30
|
+
const message = `[${code}] invalid --private-key (AGENT_PRIVATE_KEY)`
|
|
31
|
+
const help = `[${code}] https://github.com/vestauth/vestauth/issues/7`
|
|
32
|
+
|
|
33
|
+
const e = new Error(message)
|
|
34
|
+
e.code = code
|
|
35
|
+
e.help = help
|
|
36
|
+
return e
|
|
37
|
+
}
|
|
38
|
+
|
|
6
39
|
econnrefused () {
|
|
7
40
|
const code = 'ECONNREFUSED'
|
|
8
41
|
const message = `[${code}] connection refused`
|
|
@@ -17,7 +50,7 @@ class Errors {
|
|
|
17
50
|
dangerousDependencyHoist () {
|
|
18
51
|
const code = 'DANGEROUS_DEPENDENCY_HOIST'
|
|
19
52
|
const message = `[${code}] your environment has hoisted an incompatible version of a vestauth dependency: ${this.message}`
|
|
20
|
-
const help = `[${code}] https://github.com/vestauth/vestauth`
|
|
53
|
+
const help = `[${code}] https://github.com/vestauth/vestauth/issues/4`
|
|
21
54
|
|
|
22
55
|
const e = new Error(message)
|
|
23
56
|
e.code = code
|
|
@@ -1,38 +1,40 @@
|
|
|
1
|
+
const Errors = require('./errors')
|
|
1
2
|
const thumbprint = require('./thumbprint')
|
|
2
3
|
const signatureParams = require('./signatureParams')
|
|
3
4
|
const webBotAuthSignature = require('./webBotAuthSignature')
|
|
4
5
|
|
|
5
|
-
async function headers (httpMethod, uri,
|
|
6
|
-
if (!
|
|
7
|
-
if (!
|
|
6
|
+
async function headers (httpMethod, uri, id, privateKey, tag = 'web-bot-auth', nonce = null) {
|
|
7
|
+
if (!id) throw new Errors().missingId()
|
|
8
|
+
if (!privateKey) throw new Errors().missingPrivateKey()
|
|
8
9
|
|
|
9
|
-
let
|
|
10
|
+
let privateJwk
|
|
10
11
|
try {
|
|
11
|
-
|
|
12
|
-
} catch
|
|
13
|
-
throw new
|
|
12
|
+
privateJwk = JSON.parse(privateKey)
|
|
13
|
+
} catch {
|
|
14
|
+
throw new Errors().invalidPrivateKey()
|
|
15
|
+
}
|
|
16
|
+
if (!privateJwk || typeof privateJwk !== 'object') {
|
|
17
|
+
throw new Errors().invalidPrivateKey()
|
|
14
18
|
}
|
|
15
|
-
if (!privateKey || typeof privateKey !== 'object') throw new Error('invalid privateKey')
|
|
16
19
|
|
|
17
|
-
const kid = thumbprint(
|
|
18
|
-
|
|
20
|
+
const kid = thumbprint(privateJwk)
|
|
21
|
+
privateJwk.kid = kid
|
|
19
22
|
|
|
20
23
|
// // theirs
|
|
21
24
|
// const request = new Request(uri)
|
|
22
25
|
// const now = new Date()
|
|
23
26
|
// return await signatureHeaders(
|
|
24
27
|
// request,
|
|
25
|
-
// await signerFromJWK(JSON.parse(
|
|
28
|
+
// await signerFromJWK(JSON.parse(privateKey)),
|
|
26
29
|
// {
|
|
27
30
|
// created: now,
|
|
28
31
|
// expires: new Date(now.getTime() + 300_000), // now + 5 min
|
|
29
32
|
// }
|
|
30
33
|
// )
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const signatureAgent = `https://${uid}.agents.vestauth.com` // https://agent-2028e360a7f4ec28bc3cb7e6.agents.vestauth.com/.well-known/http-message-signatures-directory
|
|
35
|
+
const signatureInput = signatureParams(privateJwk.kid, tag, nonce)
|
|
36
|
+
const signature = webBotAuthSignature(httpMethod, uri, signatureInput, privateJwk)
|
|
37
|
+
const signatureAgent = `https://${id}.agents.vestauth.com` // https://agent-1234.agents.vestauth.com/.well-known/http-message-signatures-directory
|
|
36
38
|
|
|
37
39
|
return {
|
|
38
40
|
Signature: `sig1=:${signature}:`,
|
|
@@ -3,12 +3,12 @@ const env = require('./env')
|
|
|
3
3
|
function identity (raiseError = true) {
|
|
4
4
|
const publicKey = env('AGENT_PUBLIC_KEY')
|
|
5
5
|
const privateKey = env('AGENT_PRIVATE_KEY')
|
|
6
|
-
const
|
|
6
|
+
const id = env('AGENT_ID')
|
|
7
7
|
|
|
8
|
-
if (raiseError &&
|
|
8
|
+
if (raiseError && id && !(publicKey || !privateKey)) throw new Error('missing AGENT_PUBLIC_KEY, AGENT_PRIVATE_KEY, or AGENT_ID. Run [vestauth agent init]')
|
|
9
9
|
|
|
10
10
|
return {
|
|
11
|
-
|
|
11
|
+
id,
|
|
12
12
|
publicKey,
|
|
13
13
|
privateKey
|
|
14
14
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { parseDictionary } = require('structured-headers')
|
|
2
|
+
|
|
3
|
+
// example: sig1=https://agent-9aa52a556ca85ee195866c0b.agents.vestauth.com
|
|
4
|
+
function parseSignatureAgentHeader (signatureAgentHeader) {
|
|
5
|
+
const dictionary = parseDictionary(signatureAgentHeader)
|
|
6
|
+
const entry = dictionary.entries().next()
|
|
7
|
+
if (entry.done) throw new Error('Invalid Signature-Agent header: empty dictionary')
|
|
8
|
+
const [key, innerlist] = entry.value
|
|
9
|
+
const value = innerlist[0].value
|
|
10
|
+
if (!value) throw new Error('Invalid Signature-Agent header: expected a URL string')
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
key,
|
|
14
|
+
value
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = parseSignatureAgentHeader
|
|
@@ -1,7 +1,33 @@
|
|
|
1
|
-
const
|
|
1
|
+
const { http } = require('./http')
|
|
2
|
+
const buildApiError = require('./buildApiError')
|
|
3
|
+
const parseSignatureAgentHeader = require('./parseSignatureAgentHeader')
|
|
4
|
+
const verify = require('./verify')
|
|
2
5
|
|
|
3
|
-
async function providerVerify (httpMethod, uri
|
|
4
|
-
const
|
|
6
|
+
async function providerVerify (httpMethod = 'GET', uri = 'https://api.vestauth.com/whoami', headers = {}) {
|
|
7
|
+
const signatureAgent = headers['Signature-Agent']
|
|
8
|
+
const { value } = parseSignatureAgentHeader(signatureAgent) // sig1=https://agent-9aa52a556ca85ee195866c0b.agents.vestauth.com
|
|
9
|
+
|
|
10
|
+
const url = `${value}/.well-known/http-message-signatures-directory`
|
|
11
|
+
const resp = await http(url, { method: 'GET', headers: { 'Content-Type': 'application/json' } })
|
|
12
|
+
if (resp.statusCode >= 400) {
|
|
13
|
+
const json = await resp.body.json()
|
|
14
|
+
throw buildApiError(resp.statusCode, json)
|
|
15
|
+
}
|
|
16
|
+
const json = await resp.body.json()
|
|
17
|
+
|
|
18
|
+
// example json
|
|
19
|
+
// {
|
|
20
|
+
// keys: [
|
|
21
|
+
// {
|
|
22
|
+
// x: 'IaqY8f2Qp8EpS1qP7AssY0QE4I8PJDwHInLwDfB9WaU',
|
|
23
|
+
// crv: 'Ed25519',
|
|
24
|
+
// kid: 'i1B0cEjNvnSBm_TSVS87nqDj7IRfC_Q2eU-SywVxtNI',
|
|
25
|
+
// kty: 'OKP'
|
|
26
|
+
// }
|
|
27
|
+
// ]
|
|
28
|
+
// }
|
|
29
|
+
const publicJwk = json.keys[0]
|
|
30
|
+
const output = await verify(httpMethod, uri, headers, publicJwk)
|
|
5
31
|
|
|
6
32
|
return output
|
|
7
33
|
}
|
|
@@ -2,7 +2,7 @@ const crypto = require('crypto')
|
|
|
2
2
|
|
|
3
3
|
const epoch = require('./epoch')
|
|
4
4
|
|
|
5
|
-
function signatureParams (kid, tag = '
|
|
5
|
+
function signatureParams (kid, tag = 'web-bot-auth', nonce = null) {
|
|
6
6
|
const { created, expires } = epoch()
|
|
7
7
|
|
|
8
8
|
if (!nonce) nonce = crypto.randomBytes(64).toString('base64url')
|
|
@@ -3,10 +3,13 @@ const crypto = require('crypto')
|
|
|
3
3
|
const parseSignatureInputHeader = require('./parseSignatureInputHeader')
|
|
4
4
|
const stripDictionaryKey = require('./stripDictionaryKey')
|
|
5
5
|
const authorityMessage = require('./authorityMessage')
|
|
6
|
-
const
|
|
6
|
+
const publicKeyObject = require('./publicKeyObject')
|
|
7
7
|
|
|
8
|
-
function verify (httpMethod, uri,
|
|
9
|
-
const
|
|
8
|
+
function verify (httpMethod, uri, headers = {}, publicJwk) {
|
|
9
|
+
const signature = headers.Signature
|
|
10
|
+
const signatureInput = headers['Signature-Input']
|
|
11
|
+
|
|
12
|
+
const { values } = parseSignatureInputHeader(signatureInput)
|
|
10
13
|
const { expires } = values
|
|
11
14
|
|
|
12
15
|
// return early false, since expired
|
|
@@ -16,16 +19,15 @@ function verify (httpMethod, uri, signatureHeader, signatureInputHeader, publicK
|
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
const signatureParams = stripDictionaryKey(
|
|
20
|
-
const
|
|
22
|
+
const signatureParams = stripDictionaryKey(signatureInput)
|
|
23
|
+
const sig = stripDictionaryKey(signature)
|
|
21
24
|
const message = authorityMessage(uri, signatureParams)
|
|
22
|
-
const publicKeyObject = edPublicKeyObject(publicKey)
|
|
23
25
|
|
|
24
26
|
const success = crypto.verify(
|
|
25
27
|
null,
|
|
26
28
|
Buffer.from(message, 'utf8'),
|
|
27
|
-
publicKeyObject,
|
|
28
|
-
Buffer.from(
|
|
29
|
+
publicKeyObject(publicJwk),
|
|
30
|
+
Buffer.from(sig, 'base64')
|
|
29
31
|
)
|
|
30
32
|
|
|
31
33
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { verify } = require('web-bot-auth')
|
|
2
2
|
const { verifierFromJWK } = require('web-bot-auth/crypto')
|
|
3
3
|
|
|
4
|
-
async function verifyWebBotAuth (
|
|
4
|
+
async function verifyWebBotAuth (httpMethod, uri, signatureHeader, signatureInputHeader, publicKey) {
|
|
5
5
|
let success = false
|
|
6
6
|
|
|
7
7
|
const verifier = await verifierFromJWK(publicKey)
|