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