export async function GetBlueskyDID(PDS, Handle) { let request = fetch(PDS + "/xrpc/com.atproto.identity.resolveDid?handle=" + Handle, { method: "GET"}) .then((response) => response.json()); return request; } // Component 1/4 export async function GetPDSWellKnown() { let Data = await fetch("https://bsky.social/.well-known/oauth-authorization-server", {method: "GET"}) .then((response) => response.json()); return Data; } // Component 2/4 // Many thanks to https://github.com/tonyxu-io/pkce-generator. It was the base for this code. export async function CreatePKCECodeVerifier() { // Generate some Numbers let Numbers = new Uint8Array(32); crypto.getRandomValues(Numbers); // Generate a random string of characters. let CodeVerifier = ""; for (let i in Numbers) { CodeVerifier += String.fromCharCode(Numbers[i]); } // Put this random string into Base64URL format. CodeVerifier = btoa(CodeVerifier).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); return CodeVerifier; } export async function CreatePKCECodeChallenge(CodeVerifier) { // Generate a code challenge with the code verifier. // This is done by first SHA256 encrypting the CodeVerifier, then putting the outputted string into Base64URL format. let CodeChallenge = btoa(await sha256(CodeVerifier)).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); return CodeChallenge; } // Component 3/4 export async function PARrequest(PAREndpoint, State, ChallengeCode) { return await fetch(PAREndpoint, {method: "POST", body: new URLSearchParams({ response_type: "code", code_challenge_method: "S256", scope: "atproto transition:generic", client_id: "https://fedi.crowdedgames.group/oauth/client-metadata.json", redirect_uri: "https://fedi.crowdedgames.group/HTML/mail.html", code_challenge: ChallengeCode, state: State, login_hint: "crowdedgames.group" }), "Content-Type": "application/x-www-form-urlencoded"}) .then((response) => response.json()); } // Component 4/4 export async function ClientDPoP() { let KeyPair = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]); // Header var Header = {alg: "HS256", typ: "dpop+jwt", jwk: await crypto.subtle.exportKey("jwk", KeyPair.publicKey).then(function(response) {return response})}; // Payload var Payload = {}; // Payload.jti // Payload.htm // Payload.htu Payload.iat = Math.floor(new Date(Date.now()).getTime() / 1000); // Payload.nonce var sHeader = JSON.stringify(Header); var sPayload = JSON.stringify(Payload); var JWT = KJUR.jws.JWS.sign("HS256", sHeader, sPayload, "616161"); console.log(JWT); return JWT; } export async function ServerDPoP() { } export async function AssertionJWT(BlueskyClientID) { let KeyPair = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]); // Header var Header = {alg: "HS256", kid: await crypto.subtle.exportKey("jwk", KeyPair.publicKey).then(function(response) {return response})}; // Payload var Payload = {}; Payload.iss = BlueskyClientID; Payload.sub = BlueskyClientID; // Payload.aud // Payload.jti Payload.iat = Math.floor(new Date(Date.now()).getTime() / 1000); var sHeader = JSON.stringify(Header); var sPayload = JSON.stringify(Payload); var JWT = KJUR.jws.JWS.sign("HS256", sHeader, sPayload, "838383"); console.log(JWT); } // Stolen from elsewhere. // Firefox snippet; Slightly edited. async function sha256(message) { // encode as UTF-8 const MessageBuffer = new TextEncoder().encode(message); // hash the message const HashBuffer = await crypto.subtle.digest('SHA-256', MessageBuffer); // convert ArrayBuffer to Array const HashArray = Array.from(new Uint8Array(HashBuffer)); // convert this hashArray to a string let string = ""; for (let i in HashArray) { string += String.fromCharCode(HashArray[i]); } return string; }