mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-05-01 00:31:08 +00:00
feat: Add identity URL validation utilities
This commit is contained in:
parent
b56b47df82
commit
fc47399e2c
1 changed files with 84 additions and 0 deletions
84
src/lib/idURL.ts
Normal file
84
src/lib/idURL.ts
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import {
|
||||||
|
BlahIdentity,
|
||||||
|
blahIdentityDescriptionSchema,
|
||||||
|
type BlahIdentityDescription
|
||||||
|
} from '@blah-im/core/identity';
|
||||||
|
|
||||||
|
export function idURLToUsername(idURL: string): string {
|
||||||
|
const url = new URL(idURL);
|
||||||
|
return url.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IDURLValidity =
|
||||||
|
| { valid: true }
|
||||||
|
| ({ valid: false } & (
|
||||||
|
| {
|
||||||
|
reason:
|
||||||
|
| 'invalid-url'
|
||||||
|
| 'profile-invalid'
|
||||||
|
| 'identity-mismatch'
|
||||||
|
| 'identity-missing-idurl';
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
reason: 'identity-request-failed';
|
||||||
|
status?: number;
|
||||||
|
errorText?: string;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
export async function validateIDURL(url: string, identity: BlahIdentity): Promise<IDURLValidity> {
|
||||||
|
const idURL = URL.parse(url);
|
||||||
|
if (
|
||||||
|
!idURL ||
|
||||||
|
idURL.protocol !== 'https:' ||
|
||||||
|
idURL.pathname !== '/' ||
|
||||||
|
idURL.search ||
|
||||||
|
idURL.username ||
|
||||||
|
idURL.password
|
||||||
|
)
|
||||||
|
return { valid: false, reason: 'invalid-url' };
|
||||||
|
|
||||||
|
const profileFileURL = (() => {
|
||||||
|
let url = idURL;
|
||||||
|
url.pathname = '/.well-known/blah/identity.json';
|
||||||
|
return url.toString();
|
||||||
|
})();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(profileFileURL, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: { Accept: 'application/json' }
|
||||||
|
});
|
||||||
|
if (!response.ok || response.status !== 200) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'identity-request-failed',
|
||||||
|
status: response.status,
|
||||||
|
errorText: await response.text()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityDescription = await response.json();
|
||||||
|
const { data: parsedIdentityDescription } =
|
||||||
|
blahIdentityDescriptionSchema.safeParse(identityDescription);
|
||||||
|
if (!parsedIdentityDescription) return { valid: false, reason: 'profile-invalid' };
|
||||||
|
|
||||||
|
if (parsedIdentityDescription.id_key !== identity.idPublicKey.id)
|
||||||
|
return { valid: false, reason: 'identity-mismatch' };
|
||||||
|
|
||||||
|
if (parsedIdentityDescription.profile.signee.payload.id_urls.findIndex((x) => x === url) === -1)
|
||||||
|
return { valid: false, reason: 'identity-missing-idurl' };
|
||||||
|
|
||||||
|
const identityFromDescription =
|
||||||
|
await BlahIdentity.fromIdentityDescription(parsedIdentityDescription);
|
||||||
|
if (!identityFromDescription.profileSigValid)
|
||||||
|
return { valid: false, reason: 'profile-invalid' };
|
||||||
|
|
||||||
|
return { valid: true };
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'identity-request-failed',
|
||||||
|
errorText: (e as Error).message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue