vestauth 0.22.1 → 0.23.1
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 +13 -1
- package/README.md +21 -4
- package/package.json +1 -1
- package/src/cli/actions/primitives/verify.js +5 -1
- package/src/cli/actions/tool/init.js +26 -0
- package/src/cli/actions/tool/verify.js +5 -1
- package/src/cli/commands/primitives.js +1 -0
- package/src/cli/commands/tool.js +9 -0
- package/src/lib/api/postToolRegister.js +42 -0
- package/src/lib/helpers/normalizeToolHostname.js +16 -0
- package/src/lib/helpers/toolIdentity.js +17 -0
- package/src/lib/helpers/toolInit.js +37 -0
- package/src/lib/helpers/toolVerify.js +2 -2
- package/src/lib/helpers/verify.js +1 -1
- package/src/lib/main.d.ts +25 -0
- package/src/lib/tool.js +2 -0
- package/src/server/services/registerService.js +3 -1
- package/src/server/services/rotateService.js +1 -1
- package/src/server/services/whoamiService.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
[Unreleased](https://github.com/vestauth/vestauth/compare/v0.
|
|
5
|
+
[Unreleased](https://github.com/vestauth/vestauth/compare/v0.23.1...main)
|
|
6
|
+
|
|
7
|
+
## [0.23.1](https://github.com/vestauth/vestauth/compare/v0.23.0...v0.23.1) (2026-03-03)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
* Check for existing tool ([#47](https://github.com/vestauth/vestauth/pull/47))
|
|
12
|
+
|
|
13
|
+
## [0.23.0](https://github.com/vestauth/vestauth/compare/v0.22.1...v0.23.0) (2026-03-03)
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
* `vestauth tool init` preparing the way for 402 payments ([#46](https://github.com/vestauth/vestauth/pull/46))
|
|
6
18
|
|
|
7
19
|
## [0.22.1](https://github.com/vestauth/vestauth/compare/v0.22.0...v0.22.1) (2026-03-02)
|
|
8
20
|
|
package/README.md
CHANGED
|
@@ -21,6 +21,9 @@ npm i -g vestauth
|
|
|
21
21
|
```sh
|
|
22
22
|
vestauth agent init
|
|
23
23
|
vestauth agent curl https://api.vestauth.com/whoami --pp
|
|
24
|
+
vestauth agent curl https://sfs.vestauth.com/write -d '{"filepath":"/hello.md", "content":"hello"}'
|
|
25
|
+
vestauth agent curl https://sfs.vestauth.com/list
|
|
26
|
+
vestauth agent curl https://sam.vestauth.com/send -d '{"to":"you@email.com", "text":"hello from agent"}'
|
|
24
27
|
```
|
|
25
28
|
|
|
26
29
|
<details><summary>with curl 🌐 </summary><br>
|
|
@@ -128,15 +131,29 @@ vestauth agent curl https://sfs.vestauth.com/read -d '{"filepath":"/hello.md"}'
|
|
|
128
131
|
|
|
129
132
|
|
|
130
133
|
</details>
|
|
131
|
-
<details><summary>`
|
|
134
|
+
<details><summary>`SAM` Simple Agent Mail</summary><br/>
|
|
135
|
+
|
|
136
|
+
> SAM is a simple way to send email for vestauth agents.
|
|
137
|
+
>
|
|
138
|
+
> [sam.vestauth.com](https://sam.vestauth.com)
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
# send an email
|
|
142
|
+
vestauth agent curl https://sam.vestauth.com/send -d '{"to":"you@email.com", "text":"i am agent"}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
</details>
|
|
148
|
+
<details><summary>`GEO` Latitude and Longitude</summary><br/>
|
|
132
149
|
|
|
133
|
-
> GEO returns the current
|
|
150
|
+
> GEO returns the current latitude and longitude of a vestauth agent.
|
|
134
151
|
>
|
|
135
152
|
> [geo.vestauth.com](https://geo.vestauth.com)
|
|
136
153
|
|
|
137
154
|
```sh
|
|
138
|
-
#
|
|
139
|
-
vestauth agent curl https://
|
|
155
|
+
# return latitude and longitude
|
|
156
|
+
vestauth agent curl https://geo.vestauth.com/geo
|
|
140
157
|
```
|
|
141
158
|
|
|
142
159
|
|
package/package.json
CHANGED
|
@@ -25,9 +25,13 @@ async function verify (httpMethod, uri) {
|
|
|
25
25
|
'Signature-Agent': options.signatureAgent
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
const meter = {
|
|
29
|
+
cost: options.meterCost
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
const publicJwk = options.publicJwk ? JSON.parse(options.publicJwk) : undefined
|
|
29
33
|
|
|
30
|
-
const output = await primitives.verify(httpMethod, uri, headers, publicJwk)
|
|
34
|
+
const output = await primitives.verify(httpMethod, uri, headers, meter, publicJwk)
|
|
31
35
|
|
|
32
36
|
let space = 0
|
|
33
37
|
if (options.prettyPrint) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const { logger } = require('./../../../shared/logger')
|
|
2
|
+
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
|
3
|
+
|
|
4
|
+
const tool = require('./../../../lib/tool')
|
|
5
|
+
|
|
6
|
+
async function init () {
|
|
7
|
+
try {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
10
|
+
|
|
11
|
+
const output = await tool.init(options.hostname)
|
|
12
|
+
|
|
13
|
+
if (output.isNew) {
|
|
14
|
+
logger.success(`✔ tool created (${output.path}/TOOL_UID=${output.TOOL_UID})`)
|
|
15
|
+
} else {
|
|
16
|
+
logger.info(`• tool exists (${output.path}/TOOL_UID=${output.TOOL_UID})`)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
logger.help(`⮕ next run: [vestauth agent curl ${output.TOOL_HOSTNAME}/whoami]`)
|
|
20
|
+
} catch (error) {
|
|
21
|
+
catchAndLog(error)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = init
|
|
@@ -17,7 +17,11 @@ async function verify (httpMethod, uri) {
|
|
|
17
17
|
'Signature-Agent': options.signatureAgent
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const meter = {
|
|
21
|
+
cost: options.meterCost
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const output = await tool.verify(httpMethod, uri, headers, meter)
|
|
21
25
|
|
|
22
26
|
let space = 0
|
|
23
27
|
if (options.prettyPrint) {
|
|
@@ -39,6 +39,7 @@ primitives.command('verify')
|
|
|
39
39
|
.requiredOption('--signature-input <signatureInput>', '')
|
|
40
40
|
.option('--signature-agent <signatureAgent>', '')
|
|
41
41
|
.option('--public-jwk <publicJwk>', 'public JWK (json string)', env('AGENT_PUBLIC_JWK'))
|
|
42
|
+
.option('--meter-cost <meterCost>', 'vesties per invocation', '0')
|
|
42
43
|
.option('--pp, --pretty-print', 'pretty print output')
|
|
43
44
|
.action(verifyAction)
|
|
44
45
|
|
package/src/cli/commands/tool.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { Command } = require('commander')
|
|
2
|
+
const env = require('./../../lib/helpers/env')
|
|
2
3
|
|
|
3
4
|
const tool = new Command('tool')
|
|
4
5
|
|
|
@@ -6,6 +7,13 @@ tool
|
|
|
6
7
|
.description('🔨 tool')
|
|
7
8
|
.allowUnknownOption()
|
|
8
9
|
|
|
10
|
+
// vestauth tool init
|
|
11
|
+
const initAction = require('./../actions/tool/init')
|
|
12
|
+
tool.command('init')
|
|
13
|
+
.description('create tool')
|
|
14
|
+
.option('--hostname <hostname>', 'tool API hostname', env('TOOL_HOSTNAME'))
|
|
15
|
+
.action(initAction)
|
|
16
|
+
|
|
9
17
|
// vestauth tool verify
|
|
10
18
|
const verifyAction = require('./../actions/tool/verify')
|
|
11
19
|
tool.command('verify')
|
|
@@ -15,6 +23,7 @@ tool.command('verify')
|
|
|
15
23
|
.requiredOption('--signature <signature>', '')
|
|
16
24
|
.requiredOption('--signature-input <signatureInput>', '')
|
|
17
25
|
.requiredOption('--signature-agent <signatureAgent>', '')
|
|
26
|
+
.option('--meter-cost <meterCost>', 'vesties per invocation', '0')
|
|
18
27
|
.option('--pp, --pretty-print', 'pretty print output')
|
|
19
28
|
.action(verifyAction)
|
|
20
29
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { http } = require('../helpers/http')
|
|
2
|
+
const buildApiError = require('../helpers/buildApiError')
|
|
3
|
+
const agentHeaders = require('../helpers/agentHeaders')
|
|
4
|
+
|
|
5
|
+
class PostToolRegister {
|
|
6
|
+
constructor (hostname, publicJwk, privateJwk) {
|
|
7
|
+
this.hostname = hostname || 'https://api.vestauth.com'
|
|
8
|
+
this.publicJwk = publicJwk
|
|
9
|
+
this.privateJwk = privateJwk
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async run () {
|
|
13
|
+
const hostname = this.hostname
|
|
14
|
+
const url = `${hostname}/tool/register`
|
|
15
|
+
const publicJwk = this.publicJwk
|
|
16
|
+
const privateJwk = this.privateJwk
|
|
17
|
+
|
|
18
|
+
const httpMethod = 'POST'
|
|
19
|
+
const headers = await agentHeaders(httpMethod, url, 'REGISTERING', JSON.stringify(privateJwk), null, null, hostname)
|
|
20
|
+
headers['Content-Type'] = 'application/json'
|
|
21
|
+
delete headers['Signature-Agent'] // don't send Signature-Agent on registration. nothing to discover yet.
|
|
22
|
+
delete headers['signature-agent']
|
|
23
|
+
|
|
24
|
+
const resp = await http(url, {
|
|
25
|
+
method: httpMethod,
|
|
26
|
+
headers,
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
public_jwk: publicJwk
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (resp.statusCode >= 400) {
|
|
33
|
+
const json = await resp.body.json()
|
|
34
|
+
throw buildApiError(resp.statusCode, json)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const json = await resp.body.json()
|
|
38
|
+
return json
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = PostToolRegister
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const env = require('./env')
|
|
2
|
+
|
|
3
|
+
function normalizeToolHostname (hostname = null) {
|
|
4
|
+
const envHostname = env('TOOL_HOSTNAME')
|
|
5
|
+
const value = (hostname || envHostname || 'api.vestauth.com').trim()
|
|
6
|
+
const candidate = /^https?:\/\//i.test(value) ? value : `https://${value}`
|
|
7
|
+
const url = new URL(candidate)
|
|
8
|
+
|
|
9
|
+
if (url.pathname !== '/' || url.search || url.hash) {
|
|
10
|
+
throw new Error('invalid --hostname. path/query/hash are not allowed')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return url.origin
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = normalizeToolHostname
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const env = require('./env')
|
|
2
|
+
|
|
3
|
+
function toolIdentity (raiseError = true) {
|
|
4
|
+
const publicJwk = env('TOOL_PUBLIC_JWK')
|
|
5
|
+
const privateJwk = env('TOOL_PRIVATE_JWK')
|
|
6
|
+
const uid = env('TOOL_UID')
|
|
7
|
+
|
|
8
|
+
if (raiseError && uid && !(publicJwk && privateJwk)) throw new Error('missing TOOL_PUBLIC_JWK, TOOL_PRIVATE_JWK, or TOOL_UID. Run [vestauth tool init]')
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
uid,
|
|
12
|
+
publicJwk,
|
|
13
|
+
privateJwk
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = toolIdentity
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const dotenvx = require('@dotenvx/dotenvx')
|
|
2
|
+
const toolIdentity = require('./toolIdentity')
|
|
3
|
+
const keypair = require('./keypair')
|
|
4
|
+
const touch = require('./touch')
|
|
5
|
+
const normalizeToolHostname = require('./normalizeToolHostname')
|
|
6
|
+
const PostToolRegister = require('../api/postToolRegister')
|
|
7
|
+
|
|
8
|
+
async function toolInit (hostname = null) {
|
|
9
|
+
const envPath = '.env'
|
|
10
|
+
const normalizedHostname = normalizeToolHostname(hostname)
|
|
11
|
+
const shouldPersistHostname = normalizedHostname !== 'https://api.vestauth.com'
|
|
12
|
+
|
|
13
|
+
// keypair
|
|
14
|
+
const currentPrivateJwk = toolIdentity(false).privateJwk
|
|
15
|
+
const kp = keypair(currentPrivateJwk, 'tool')
|
|
16
|
+
|
|
17
|
+
touch(envPath)
|
|
18
|
+
|
|
19
|
+
// register tool
|
|
20
|
+
const tool = await new PostToolRegister(normalizedHostname, kp.publicJwk, kp.privateJwk).run()
|
|
21
|
+
dotenvx.set('TOOL_UID', tool.uid, { path: envPath, plain: true, quiet: true })
|
|
22
|
+
dotenvx.set('TOOL_PUBLIC_JWK', JSON.stringify(kp.publicJwk), { path: envPath, plain: true, quiet: true })
|
|
23
|
+
dotenvx.set('TOOL_PRIVATE_JWK', JSON.stringify(kp.privateJwk), { path: envPath, plain: true, quiet: true })
|
|
24
|
+
if (shouldPersistHostname) {
|
|
25
|
+
dotenvx.set('TOOL_HOSTNAME', normalizedHostname, { path: envPath, plain: true, quiet: true })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
TOOL_UID: tool.uid,
|
|
30
|
+
TOOL_PUBLIC_JWK: kp.publicJwk,
|
|
31
|
+
TOOL_HOSTNAME: normalizedHostname,
|
|
32
|
+
path: envPath,
|
|
33
|
+
isNew: tool.is_new
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = toolInit
|
|
@@ -4,7 +4,7 @@ const extractHostAndHostname = require('./extractHostAndHostname')
|
|
|
4
4
|
const trustedFqdn = require('./trustedFqdn')
|
|
5
5
|
const Errors = require('./errors')
|
|
6
6
|
|
|
7
|
-
async function toolVerify (httpMethod, uri, headers = {}, serverHostname = null) {
|
|
7
|
+
async function toolVerify (httpMethod, uri, headers = {}, meter = {}, serverHostname = null) {
|
|
8
8
|
if (!httpMethod) {
|
|
9
9
|
throw new Errors().missingHttpMethod()
|
|
10
10
|
}
|
|
@@ -33,7 +33,7 @@ async function toolVerify (httpMethod, uri, headers = {}, serverHostname = null)
|
|
|
33
33
|
throw new Errors().untrustedSignatureAgent()
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
return verify(httpMethod, uri, headers)
|
|
36
|
+
return verify(httpMethod, uri, headers, meter)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
module.exports = toolVerify
|
|
@@ -77,7 +77,7 @@ async function resolvePublicJwk ({ signatureInput, signatureAgent, publicJwk })
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
async function verify (httpMethod, uri, headers = {}, publicJwk) {
|
|
80
|
+
async function verify (httpMethod, uri, headers = {}, meter = {}, publicJwk) {
|
|
81
81
|
const signature = headers.Signature || headers.signature
|
|
82
82
|
const signatureInput = headers['Signature-Input'] || headers['signature-input']
|
|
83
83
|
const signatureAgent = headers['Signature-Agent'] || headers['signature-agent']
|
package/src/lib/main.d.ts
CHANGED
|
@@ -46,6 +46,11 @@ export interface VerifyResult {
|
|
|
46
46
|
well_known_url?: string
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
export interface Meter {
|
|
50
|
+
cost?: string | number
|
|
51
|
+
[prop: string]: unknown
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
export interface AgentApi {
|
|
50
55
|
/**
|
|
51
56
|
* Creates (or reuses) an Ed25519 keypair, registers the agent, and writes to `.env`.
|
|
@@ -93,6 +98,23 @@ export interface ProviderApi {
|
|
|
93
98
|
verify(httpMethod: HttpMethod, uri: string, headers?: HeaderBag): Promise<VerifyResult>
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
export interface ToolApi {
|
|
102
|
+
/**
|
|
103
|
+
* Creates (or reuses) an Ed25519 keypair, registers the tool, and writes to `.env`.
|
|
104
|
+
*/
|
|
105
|
+
init(): Promise<{
|
|
106
|
+
TOOL_PUBLIC_JWK: PublicJwk
|
|
107
|
+
TOOL_UID: string
|
|
108
|
+
path: string
|
|
109
|
+
isNew: boolean
|
|
110
|
+
}>
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Verifies a signed request (fetching the agent's discovery keys when needed).
|
|
114
|
+
*/
|
|
115
|
+
verify(httpMethod: HttpMethod, uri: string, headers?: HeaderBag): Promise<VerifyResult>
|
|
116
|
+
}
|
|
117
|
+
|
|
96
118
|
export interface PrimitivesApi {
|
|
97
119
|
/**
|
|
98
120
|
* Creates an Ed25519 keypair. If `existingPrivateJwk` is provided, it is reused.
|
|
@@ -121,16 +143,19 @@ export interface PrimitivesApi {
|
|
|
121
143
|
httpMethod: HttpMethod,
|
|
122
144
|
uri: string,
|
|
123
145
|
headers?: HeaderBag,
|
|
146
|
+
meter?: Meter,
|
|
124
147
|
publicJwk?: PublicJwk
|
|
125
148
|
): Promise<VerifyResult>
|
|
126
149
|
}
|
|
127
150
|
|
|
128
151
|
export const agent: AgentApi
|
|
152
|
+
export const tool: ToolApi
|
|
129
153
|
export const provider: ProviderApi
|
|
130
154
|
export const primitives: PrimitivesApi
|
|
131
155
|
|
|
132
156
|
declare const _default: {
|
|
133
157
|
agent: AgentApi
|
|
158
|
+
tool: ToolApi
|
|
134
159
|
provider: ProviderApi
|
|
135
160
|
primitives: PrimitivesApi
|
|
136
161
|
}
|
package/src/lib/tool.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const primitives = require('./../../lib/primitives')
|
|
2
2
|
|
|
3
3
|
class RegisterService {
|
|
4
|
-
constructor ({ models, httpMethod, uri, headers, publicJwk }) {
|
|
4
|
+
constructor ({ models, httpMethod, uri, headers, meter, publicJwk }) {
|
|
5
5
|
this.models = models
|
|
6
6
|
this.httpMethod = httpMethod
|
|
7
7
|
this.uri = uri
|
|
8
8
|
this.headers = headers
|
|
9
|
+
this.meter = meter
|
|
9
10
|
this.publicJwk = publicJwk
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -14,6 +15,7 @@ class RegisterService {
|
|
|
14
15
|
this.httpMethod,
|
|
15
16
|
this.uri,
|
|
16
17
|
this.headers,
|
|
18
|
+
this.meter,
|
|
17
19
|
this.publicJwk
|
|
18
20
|
)
|
|
19
21
|
|
|
@@ -11,7 +11,7 @@ class RotateService {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
async run () {
|
|
14
|
-
const remoteAgent = await tool.verify(this.httpMethod, this.uri, this.headers, this.serverHostname)
|
|
14
|
+
const remoteAgent = await tool.verify(this.httpMethod, this.uri, this.headers, {}, this.serverHostname)
|
|
15
15
|
// uid: 'agent-6d2140af72bcefcedd4b44ab',
|
|
16
16
|
// kid: 'Tx3W50MU5wMQ5I77z5DUGtbcs3ZPLlxfWx14pzpo5Fo',
|
|
17
17
|
// public_jwk: {
|