From 8052582b5e34cb537fa7b2f96acc39935bdb5fc9 Mon Sep 17 00:00:00 2001 From: CatAClock Date: Wed, 30 Apr 2025 16:47:09 -0700 Subject: [PATCH] test later --- JS/BlueskyAPI.js | 43 +++++++++++++++++++++++++++++++++---------- JS/MastodonAPI.js | 7 +++---- JS/setting.js | 9 ++++++--- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/JS/BlueskyAPI.js b/JS/BlueskyAPI.js index f294473..f400404 100644 --- a/JS/BlueskyAPI.js +++ b/JS/BlueskyAPI.js @@ -1,9 +1,16 @@ -export async function GetBlueskyDID(PDS, Handle) { - let request = fetch(PDS + "/xrpc/com.atproto.identity.resolveDid?handle=" + Handle, { method: "GET"}) +export async function GetBlueskyDID(PDS, Handle, NonceName, AccessToken) { + let DPoP = ClientDPoPPDS("GET", PDS + "/xrpc/com.atproto.identity.resolveDid", document.cookie.split("; ").find((row) => row.startsWith(NonceName + "="))?.split("="), AccessToken); + let request = fetch(PDS + "/xrpc/com.atproto.identity.resolveDid?handle=" + Handle, { method: "GET", headers: {"Authorization": "DPoP " + AccessToken, "DPoP": DPoP}) .then((response) => response.json()); return request; } +// Component 0/4 (refresh) +// is this even required? +export async function RefreshToken() { + +} + // Component 1/4 export async function GetPDSWellKnown() { let Data = await fetch("https://bsky.social/.well-known/oauth-authorization-server", {method: "GET"}) @@ -45,7 +52,7 @@ export async function AuthRequest(TokenEndpoint, ChallengeVerifier, code, DPoP) } // Component 4/4 -export async function ClientDPoP(POSTorGET, RequestURL, DPoPNonce) { +export async function ClientDPoPToken(POSTorGET, RequestURL, DPoPNonce) { let KeyPair = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]); // Header @@ -80,23 +87,39 @@ export async function ClientDPoP(POSTorGET, RequestURL, DPoPNonce) { } // So far does nothing? Don't touch :3 -export async function AssertionJWT() { +export async function ClientDPoPPDS(POSTorGET, RequestURL, DPoPNonce, AccessToken) { 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})}; + var Header = {typ: "dpop+jwt", alg: "ES256", jwk: + await crypto.subtle.exportKey("jwk", KeyPair.publicKey) + .then(function(response) { + delete response["key_ops"]; + delete response["ext"]; + delete response["alg"]; + return response}) + }; // Payload var Payload = {}; - Payload.iss = "https://fedi.crowdedgames.group/oauth/client-metadata.json"; - Payload.sub = "https://fedi.crowdedgames.group/oauth/client-metadata.json"; - // Payload.aud Payload.jti = crypto.randomUUID(); + Payload.htm = POSTorGET; + Payload.htu = RequestURL; Payload.iat = Math.floor(new Date(Date.now()).getTime() / 1000); + Payload.nonce = DPoPNonce; + Payload.ath = await CreatePKCECodeChallenge(AccessToken); var sHeader = JSON.stringify(Header); var sPayload = JSON.stringify(Payload); - var JWT = KJUR.jws.JWS.sign("HS256", sHeader, sPayload, "838383"); + var JWT = KJUR.jws.JWS.sign("ES256", sHeader, sPayload, + await crypto.subtle.exportKey("jwk", KeyPair.privateKey) + .then(function(response) { + delete response["key_ops"]; + delete response["ext"]; + delete response["alg"]; + return response}) + ); + return JWT; } export async function HandleAuthorization(BlueskyPKCEverifer, BlueskyPKCEchallenge, BlueskyNonce) { @@ -132,7 +155,7 @@ export async function GainTokens(PKCEcodeName, NonceName, AccessToken, RefreshTo // Check to see if something's a miss... if ((document.location.href.split("state=").length > 1 && document.location.href.split("iss=").length > 1 && document.location.href.split("code=").length > 1) && document.cookie.split("; ").find((row) => row.startsWith(PKCEcodeName + "="))?.split("=").length > 1 && document.cookie.split("; ").find((row) => row.startsWith(AccessToken + "="))?.split("=").length == 1) { // Create varaibles, be aware of waits because of internet. - let DPoP = await ClientDPoP("POST", "https://bsky.social/oauth/token", document.cookie.split("; ").find((row) => row.startsWith(NonceName + "="))?.split("=")[1]); + let DPoP = await ClientDPoPToken("POST", "https://bsky.social/oauth/token", document.cookie.split("; ").find((row) => row.startsWith(NonceName + "="))?.split("=")[1]); let PKCE = document.cookie.split("; ").find((row) => row.startsWith(PKCEcodeName + "="))?.split("=")[1]; let code = document.location.href.split("code=")[1]; // Authentication diff --git a/JS/MastodonAPI.js b/JS/MastodonAPI.js index 62a0920..c3c0ea8 100644 --- a/JS/MastodonAPI.js +++ b/JS/MastodonAPI.js @@ -1,5 +1,4 @@ export const Scopes = "read write follow push"; -let Origin = document.location.href; // Gets the public timeline. export async function GetPublicTimeline(Local = false, Remote = false, Website) { @@ -75,13 +74,13 @@ export async function HandleAuthentication(Website, CookieClientID, CookieClient Website = "https://" + Website; } // Registering the app. - InstanceData = await fetch(Website + "/api/v1/apps?client_name=Channel Viewer&redirect_uris=" + Origin + "&scopes=" + Scopes, {method: "POST"}) + InstanceData = await fetch(Website + "/api/v1/apps?client_name=Channel Viewer&redirect_uris=" + document.location.href + "&scopes=" + Scopes, {method: "POST"}) .then((response) => response.json()); // Save the client stuff as cookies. document.cookie = CookieClientID + "=" + InstanceData.client_id + ";samesite=strict;path=/;expires=Fri, 31 Dec 9999 23:59:59 GMT;"; document.cookie = CookieClientSecret + "=" + InstanceData.client_secret + ";samesite=strict;path=/;expires=Fri, 31 Dec 9999 23:59:59 GMT;"; // Now authenticate the app. - document.location.href = Website + "/oauth/authorize?client_id=" + InstanceData.client_id + "&redirect_uri=" + Origin + "&response_type=code&scope=" + Scopes; + document.location.href = Website + "/oauth/authorize?client_id=" + InstanceData.client_id + "&redirect_uri=" + document.location.href + "&response_type=code&scope=" + Scopes; } // This specific functino goes after HandleAuthentication for when login happens. @@ -92,7 +91,7 @@ export async function GainToken(Website, CookieClientID, CookieClientSecret, Coo let ClientID = document.cookie.split("; ").find((row) => row.startsWith(CookieClientID + "="))?.split("=")[1]; let ClientSecret = document.cookie.split("; ").find((row) => row.startsWith(CookieClientSecret + "="))?.split("=")[1]; - let AuthenticationToken = await fetch(Website + "/oauth/token?client_id=" + ClientID + "&client_secret=" + ClientSecret + "&redirect_uri=" + Origin + "&grant_type=authorization_code&code=" + code, {method: "POST"}) + let AuthenticationToken = await fetch(Website + "/oauth/token?client_id=" + ClientID + "&client_secret=" + ClientSecret + "&redirect_uri=" + document.location.href + "&grant_type=authorization_code&code=" + code, {method: "POST"}) .then((response) => response.json()); // Cookify These document.cookie = CookieAccessToken + "=" + AuthenticationToken.access_token + ";samesite=strict;path=/;expires=Fri, 31 Dec 9999 23:59:59 GMT;"; diff --git a/JS/setting.js b/JS/setting.js index 57d122b..965d14b 100644 --- a/JS/setting.js +++ b/JS/setting.js @@ -92,8 +92,9 @@ function CheckLogin() { MastodonLogoutButton.setAttribute("style", ""); } else { // Auto log in - MastodonAPI.GainToken(MastodonWebsite, MastodonClientID, MastodonClientSecret, MastodonAccessToken, MastodonTokenType); + await MastodonAPI.GainToken(MastodonWebsite, MastodonClientID, MastodonClientSecret, MastodonAccessToken, MastodonTokenType); } + // Check for a bluesky token. if ((document.location.href.split("state=").length == 1 && document.location.href.split("iss=").length == 1 && document.location.href.split("code=").length == 1) && document.cookie.split("; ").find((row) => row.startsWith(BlueskyAccessToken + "="))?.split("=").length > 1) { // Swap the buttons BlueskyLoginButton.remove(); @@ -101,11 +102,13 @@ function CheckLogin() { BlueskyLogoutButton.setAttribute("style", ""); } else { // Auto log in - BlueskyAPI.GainTokens(BlueskyPKCEverifer, BlueskyNonce, BlueskyAccessToken, BlueskyRefreshToken); + await BlueskyAPI.GainTokens(BlueskyPKCEverifer, BlueskyNonce, BlueskyAccessToken, BlueskyRefreshToken); } - // Check for a bluesky token. } // Runs on website start. // Remove traces of "login". CheckLogin(); + +// TESTING! +BlueskyAPI.GetBlueskyDID(BlueskyPDS, "crowdedgames.group", document.cookie.split("; ").find((row) => row.startsWith(BlueskyAccessToken + "="))?.split("=")[1]);