Skip to content

Commit 5ed8ed1

Browse files
Components check now done on params.components rather than on filled variable, Refactored signatureHeaders and signatureHeadersSync common code into getSigningOptions, ran 'npm run lint'
1 parent 3dd3248 commit 5ed8ed1

File tree

5 files changed

+47
-62
lines changed

5 files changed

+47
-62
lines changed

.github/workflows/pullrequest.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ jobs:
6161
name: Deploy Rust Crates
6262
timeout-minutes: 5
6363
env:
64-
# This token can be regenerated by visiting https://crates.io/me,
65-
# generating a new API token with `publish-update` permissions,
66-
# scoping it to just `web-bot-auth` and `http-signature-directory`
67-
# crates, and uploading to Github.
68-
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_API_TOKEN }}
64+
# This token can be regenerated by visiting https://crates.io/me,
65+
# generating a new API token with `publish-update` permissions,
66+
# scoping it to just `web-bot-auth` and `http-signature-directory`
67+
# crates, and uploading to Github.
68+
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_API_TOKEN }}
6969
strategy:
7070
matrix:
7171
os: [ubuntu-24.04]
@@ -87,7 +87,7 @@ jobs:
8787
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
8888
- name: Set rust toolchain
8989
run: rustup override set 1.87
90-
- run: cargo publish -p web-bot-auth # will fail if we don't bump the version
90+
- run: cargo publish -p web-bot-auth # will fail if we don't bump the version
9191
continue-on-error: true
9292
- run: cargo publish -p http-signature-directory # will fail if we don't bump the version
93-
continue-on-error: true
93+
continue-on-error: true

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ This deployment allows to test your implementation.
4343

4444
This repository uses [npm](https://docs.npmjs.com/cli/v11/using-npm/workspaces) and [cargo](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) workspaces. There are several packages which it provides:
4545

46-
| Package | Language | Description |
47-
| :--------------------------------------------------------- | :--------- | :------------------------------------------------------------------------------------- |
48-
| [http-message-sig](./packages/http-message-sig/) | TypeScript | HTTP Message Signatures as defined in RFC 9421 |
49-
| [jsonwebkey-thumbprint](./packages/jsonwebkey-thumbprint/) | TypeScript | JWK Thumbprint as defined in RFC 7638 |
50-
| [web-bot-auth](./packages/web-bot-auth/) | TypeScript | HTTP Message Signatures for Bots as defined in draft-meunier-web-bot-auth-architecture |
51-
| [web-bot-auth](./crates/web-bot-auth/) | Rust | HTTP Message Signatures for Bots as defined in draft-meunier-web-bot-auth-architecture |
52-
| [http-signature-directory](./crates/http-signature-directory/)| Rust | Validates whether an HTTP message signature directory is correctly signed and valid |
46+
| Package | Language | Description |
47+
| :------------------------------------------------------------- | :--------- | :------------------------------------------------------------------------------------- |
48+
| [http-message-sig](./packages/http-message-sig/) | TypeScript | HTTP Message Signatures as defined in RFC 9421 |
49+
| [jsonwebkey-thumbprint](./packages/jsonwebkey-thumbprint/) | TypeScript | JWK Thumbprint as defined in RFC 7638 |
50+
| [web-bot-auth](./packages/web-bot-auth/) | TypeScript | HTTP Message Signatures for Bots as defined in draft-meunier-web-bot-auth-architecture |
51+
| [web-bot-auth](./crates/web-bot-auth/) | Rust | HTTP Message Signatures for Bots as defined in draft-meunier-web-bot-auth-architecture |
52+
| [http-signature-directory](./crates/http-signature-directory/) | Rust | Validates whether an HTTP message signature directory is correctly signed and valid |
5353

5454
## Security Considerations
5555

crates/http-signature-directory/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ This is an opinionated validator:
1818
- [Security Considerations](#security-considerations)
1919
- [License](#license)
2020

21-
2221
## Usage
2322

2423
```

packages/web-bot-auth/src/index.ts

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export {
66
type SignatureHeaders,
77
type Signer,
88
type SignerSync,
9+
type SignOptions,
910
Tag,
1011
directoryResponseHeaders,
1112
} from "http-message-sig";
@@ -55,13 +56,13 @@ export function validateNonce(nonce: string): boolean {
5556
}
5657
}
5758

58-
export function signatureHeaders<
59+
function getSigningOptions<
5960
T extends httpsig.RequestLike | httpsig.ResponseLike,
6061
>(
6162
message: T,
6263
signer: httpsig.Signer,
6364
params: SignatureParams
64-
): Promise<httpsig.SignatureHeaders> {
65+
): httpsig.SignOptions {
6566
if (params.created.getTime() > params.expires.getTime()) {
6667
throw new Error("created should happen before expires");
6768
}
@@ -75,21 +76,24 @@ export function signatureHeaders<
7576
}
7677
}
7778
const signatureAgent = httpsig.extractHeader(message, SIGNATURE_AGENT_HEADER);
78-
let components: string[] | undefined = params.components;
79-
if(!components) {
80-
// not the ideal check, but extractHeader returns "" instead of throwing or null when the header does not exist
79+
let components: string[];
80+
if (!params.components) {
81+
// `extractHeader` returns "" instead of throwing or null when the header does not exist
8182
if (!signatureAgent) {
8283
components = REQUEST_COMPONENTS_WITHOUT_SIGNATURE_AGENT;
8384
} else {
84-
components = REQUEST_COMPONENTS
85+
components = REQUEST_COMPONENTS;
8586
}
8687
} else {
87-
if(signatureAgent && components.indexOf("SIGNATURE_AGENT_HEADER") === -1)
88-
{
89-
throw new Error(`${SIGNATURE_AGENT_HEADER} is required in params.component when included as a header param`);
88+
if (signatureAgent && components.indexOf("SIGNATURE_AGENT_HEADER") === -1) {
89+
throw new Error(
90+
`${SIGNATURE_AGENT_HEADER} is required in params.component when included as a header param`
91+
);
9092
}
93+
components = params.components;
9194
}
92-
return httpsig.signatureHeaders(message, {
95+
96+
return {
9397
signer,
9498
components,
9599
created: params.created,
@@ -98,7 +102,20 @@ export function signatureHeaders<
98102
keyid: signer.keyid,
99103
key: params.key,
100104
tag: HTTP_MESSAGE_SIGNAGURE_TAG,
101-
});
105+
};
106+
}
107+
108+
export function signatureHeaders<
109+
T extends httpsig.RequestLike | httpsig.ResponseLike,
110+
>(
111+
message: T,
112+
signer: httpsig.Signer,
113+
params: SignatureParams
114+
): Promise<httpsig.SignatureHeaders> {
115+
return httpsig.signatureHeaders(
116+
message,
117+
getSigningOptions(message, signer, params)
118+
);
102119
}
103120

104121
export function signatureHeadersSync<
@@ -108,41 +125,10 @@ export function signatureHeadersSync<
108125
signer: httpsig.SignerSync,
109126
params: SignatureParams
110127
): httpsig.SignatureHeaders {
111-
if (params.created.getTime() > params.expires.getTime()) {
112-
throw new Error("created should happen before expires");
113-
}
114-
let nonce = params.nonce;
115-
if (!nonce) {
116-
nonce = generateNonce();
117-
} else {
118-
if (!validateNonce(nonce)) {
119-
throw new Error("nonce is not a valid uint32");
120-
}
121-
}
122-
const signatureAgent = httpsig.extractHeader(message, SIGNATURE_AGENT_HEADER);
123-
let components: string[] | undefined = params.components;
124-
if(!components) {
125-
// not the ideal check, but extractHeader returns "" instead of throwing or null when the header does not exist
126-
if (!signatureAgent) {
127-
components = REQUEST_COMPONENTS_WITHOUT_SIGNATURE_AGENT;
128-
} else {
129-
components = REQUEST_COMPONENTS
130-
}
131-
} else {
132-
if(signatureAgent && components.indexOf("SIGNATURE_AGENT_HEADER") === -1)
133-
{
134-
throw new Error(`${SIGNATURE_AGENT_HEADER} is required in params.component when included as a header param`);
135-
}
136-
}
137-
return httpsig.signatureHeadersSync(message, {
138-
signer,
139-
components,
140-
created: params.created,
141-
expires: params.expires,
142-
nonce,
143-
keyid: signer.keyid,
144-
tag: HTTP_MESSAGE_SIGNAGURE_TAG,
145-
});
128+
return httpsig.signatureHeadersSync(
129+
message,
130+
getSigningOptions(message, signer, params)
131+
);
146132
}
147133

148134
export type Verify<T> = (

packages/web-bot-auth/test/test_data/web_bot_auth_architecture_v1.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@
7777
"signature_input": "sig2=(\"@authority\" \"signature-agent\");created=1735689600;keyid=\"poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U\";alg=\"ed25519\";expires=1735693200;nonce=\"e8N7S2MFd/qrd6T2R3tdfAuuANngKI7LFtKYI/vowzk4lAZYadIX6wW25MwG7DCT9RUKAJ0qVkU0mEeLElW1qg==\";tag=\"web-bot-auth\"",
7878
"signature_agent": "\"https://signature-agent.test\""
7979
}
80-
]
80+
]

0 commit comments

Comments
 (0)