Testing merge (#13)

Reviewed-on: #13
This commit is contained in:
CatAClock 2025-05-05 23:55:56 +00:00
parent 89e2c54d3e
commit 9b52f641cb
11 changed files with 226 additions and 186 deletions

View file

@ -13,9 +13,17 @@
<body style="margin: 0px; text-align: center;">
<header>
<h1>Post</h1>
<textarea cols="50" rows="25" class="text" placeholder="status here..."></textarea>
<p class="button">POST!</p>
</header>
<textarea cols="50" rows="25" class="Text" placeholder="status here..."></textarea>
<div>
<select class="PostVisibility">
<option value="Public">Public Post</option>
<option value="Quiet">Quiet Public Post</option>
<option value="Friend">Friends Only Post</option>
<option value="Private">Private Post</option>
</select>
</div>
<p class="Button">POST!</p>
<p onclick="window.location.href = window.location.origin"><b>Back</b></p>
</body>
</html>

View file

@ -17,10 +17,10 @@
<p class="Local">Toggle Local</p>
<p class="Remote">Toggle Remote</p>
<p class="Login Mastodon"><em>Login to Mastodon</em></p>
<input type="text" class="WebInput Mastodon" placeholder="The website your account is on."/>
<input type="text" class="WebInput Mastodon" placeholder="Website (mastodon.social)"/>
<p class="Logout Mastodon" style="visibility: hidden;"><em>Logout of Mastodon</em></p>
<p class="Login Bluesky"><em>Login to Bluesky</em></p>
<input type="text" class="WebInput Bluesky" />
<input type="text" class="WebInput Bluesky" placeholder="Website (bsky.social)" />
<p class="Logout Bluesky" style="visibility: hidden;"><em>Logout of Bluesky</em></p>
<p onclick="window.location.href = window.location.origin"><b>Back</b></p>
</body>

View file

@ -1,24 +1,7 @@
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";
export async function GetBlueskyDID(PDS, Handle) {
let DPoP = await ClientDPoPPDS("GET", PDS + "/xrpc/com.atproto.identity.resolveHandle?handle=" + Handle);
let request = fetch(PDS + "/xrpc/com.atproto.identity.resolveHandle?handle=" + Handle, { method: "GET", headers: {"Authorization": "DPoP " + Cookie.GetCookie(Cookie.BlueskyAccessToken), "DPoP": DPoP}});
let body = await request.then((response) => response.json());
let status = await request.then((response) => response.status);
let header = await request.then((response) => response.headers.get("dpop-nonce"));
if (status == 401) {
if (body.message.includes("DPoP nonce mismatch")) {
await Cookie.InputCookie(Cookie.BlueskyNonce, header);
}
if (body.message.includes("claim timestamp check failed")) {
await RefreshTokens();
}
body = await GetBlueskyDID(PDS, Handle);
}
return body;
}
export async function CreatePost(PDS, DID, Text) {
export async function CreatePost(DID, Text) {
let PDS = localStorage.getItem(Variables.BlueskyPDS);
let Json = {
"$type": "app.bsky.feed.post",
"text": Text,
@ -30,18 +13,49 @@ export async function CreatePost(PDS, DID, Text) {
"record": Json
}
let DPoP = await ClientDPoPPDS("POST", PDS + "/xrpc/com.atproto.repo.createRecord");
let request = fetch(PDS + "/xrpc/com.atproto.repo.createRecord", { body: JSON.stringify(RequestBody), method: "POST", headers: {"Content-Type": "application/json", "Authorization": "DPoP " + Cookie.GetCookie(Cookie.BlueskyAccessToken), "DPoP": DPoP}});
let request = fetch(PDS + "/xrpc/com.atproto.repo.createRecord", { body: JSON.stringify(RequestBody), method: "POST", headers: {"Content-Type": "application/json", "Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
let body = await request.then((response) => response.json());
let status = await request.then((response) => response.status);
let header = await request.then((response) => response.headers.get("dpop-nonce"));
if (status == 401) {
if (body.message.includes("DPoP nonce mismatch")) {
await Cookie.InputCookie(Cookie.BlueskyNonce, header);
await localStorage.setItem(Variables.BlueskyNonce, header);
}
if (body.message.includes("claim timestamp check failed")) {
await RefreshTokens();
}
body = await CreatePost(PDS, DID, Text);
body = await CreatePost(DID, Text);
}
return body;
}
export async function SetThreadGate(DID, Post, VisibilitySettings) {
let PDS = localStorage.getItem(Variables.BlueskyPDS);
let Json = {
"$type": "app.bsky.feed.threadgate",
"post": Post,
"allow": VisibilitySettings,
"createdAt": new Date(Date.now()).toISOString()
}
let RequestBody = {
"repo": DID,
"collection": "app.bsky.feed.threadgate",
"record": Json,
"rkey": Post.split("/")[Post.split("/").length - 1]
}
let DPoP = await ClientDPoPPDS("POST", PDS + "/xrpc/com.atproto.repo.createRecord");
let request = fetch(PDS + "/xrpc/com.atproto.repo.createRecord", { body: JSON.stringify(RequestBody), method: "POST", headers: {"Content-Type": "application/json", "Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
let body = await request.then((response) => response.json());
let status = await request.then((response) => response.status);
let header = await request.then((response) => response.headers.get("dpop-nonce"));
if (status == 401) {
if (body.message.includes("DPoP nonce mismatch")) {
await localStorage.setItem(Variables.BlueskyNonce, header);
}
if (body.message.includes("claim timestamp check failed")) {
await RefreshTokens();
}
body = await SetThreadGate(DID, Post, VisibilitySettings);
}
return body;
}
@ -91,8 +105,8 @@ async function ReauthRequest(TokenEndpoint, Token, DPoP) {
// Component 4/4
export async function ClientDPoPToken(POSTorGET, RequestURL) {
let PublicKey = await crypto.subtle.importKey("jwk", JSON.parse(Cookie.GetCookie(Cookie.BlueskyPublicKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"]);
let PrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(Cookie.GetCookie(Cookie.BlueskyPrivateKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["sign"]);
let PublicKey = await crypto.subtle.importKey("jwk", JSON.parse(localStorage.getItem(Variables.BlueskyPublicKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"]);
let PrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(localStorage.getItem(Variables.BlueskyPrivateKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["sign"]);
// Header
var Header = {typ: "dpop+jwt", alg: "ES256", jwk:
@ -110,7 +124,7 @@ export async function ClientDPoPToken(POSTorGET, RequestURL) {
Payload.htm = POSTorGET;
Payload.htu = RequestURL;
Payload.iat = Math.floor(new Date(Date.now()).getTime() / 1000);
Payload.nonce = Cookie.GetCookie(Cookie.BlueskyNonce);
Payload.nonce = localStorage.getItem(Variables.BlueskyNonce);
var sHeader = JSON.stringify(Header);
var sPayload = JSON.stringify(Payload);
@ -126,8 +140,8 @@ export async function ClientDPoPToken(POSTorGET, RequestURL) {
}
export async function ClientDPoPPDS(POSTorGET, RequestURL) {
let PublicKey = await crypto.subtle.importKey("jwk", JSON.parse(Cookie.GetCookie(Cookie.BlueskyPublicKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"]);
let PrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(Cookie.GetCookie(Cookie.BlueskyPrivateKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["sign"]);
let PublicKey = await crypto.subtle.importKey("jwk", JSON.parse(localStorage.getItem(Variables.BlueskyPublicKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"]);
let PrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(localStorage.getItem(Variables.BlueskyPrivateKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["sign"]);
// Header
var Header = {typ: "dpop+jwt", alg: "ES256", jwk:
@ -145,8 +159,8 @@ export async function ClientDPoPPDS(POSTorGET, RequestURL) {
Payload.htm = POSTorGET;
Payload.htu = RequestURL;
Payload.iat = Math.floor(new Date(Date.now()).getTime() / 1000);
Payload.nonce = Cookie.GetCookie(Cookie.BlueskyNonce);
Payload.ath = await CreatePKCECodeChallenge(Cookie.GetCookie(Cookie.BlueskyAccessToken));
Payload.nonce = localStorage.getItem(Variables.BlueskyNonce);
Payload.ath = await CreatePKCECodeChallenge(localStorage.getItem(Variables.BlueskyAccessToken));
var sHeader = JSON.stringify(Header);
var sPayload = JSON.stringify(Payload);
@ -161,7 +175,13 @@ export async function ClientDPoPPDS(POSTorGET, RequestURL) {
return JWT;
}
export async function HandleAuthorization() {
export async function HandleAuthorization(Website) {
// Quickly check to see if it has something before :// so it doesn't screw the link.
if (Website.toLowerCase().split("://").length > 1) {
Website = "https://" + Website.split("://")[1];
} else {
Website = "https://" + Website;
}
// Declare Variables
let KeyPair = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]);
@ -172,38 +192,42 @@ export async function HandleAuthorization() {
let PKCEverifier = await CreatePKCECodeVerifier();
let PKCEchallenge = await CreatePKCECodeChallenge(PKCEverifier);
// Save these
Cookie.InputCookie(Cookie.BlueskyPKCEVerifier, PKCEverifier);
Cookie.InputCookie(Cookie.BlueskyPKCEChallenge, PKCEchallenge);
localStorage.setItem(Variables.BlueskyPKCEVerifier, PKCEverifier);
localStorage.setItem(Variables.BlueskyPKCEChallenge, PKCEchallenge);
// PAR request (beginning)
let PAR = PARrequest(WellKnown.pushed_authorization_request_endpoint, State, PKCEchallenge);
let body = await PAR.then((response) => response.json());
let nonce = await PAR.then((response) => response.headers.get("dpop-nonce"));
// Save nonce
Cookie.InputCookie(Cookie.BlueskyNonce, nonce);
localStorage.setItem(Variables.BlueskyNonce, nonce);
// Export keys
let ExportedKey1 = await crypto.subtle.exportKey("jwk", KeyPair.publicKey);
let ExportedKey2 = await crypto.subtle.exportKey("jwk", KeyPair.privateKey);
// Convert them into a good format.
Cookie.InputCookie(Cookie.BlueskyPublicKey, JSON.stringify(ExportedKey1));
Cookie.InputCookie(Cookie.BlueskyPrivateKey, JSON.stringify(ExportedKey2));
localStorage.setItem(Variables.BlueskyPublicKey, JSON.stringify(ExportedKey1));
localStorage.setItem(Variables.BlueskyPrivateKey, JSON.stringify(ExportedKey2));
// Now we need to authenticate. Make sure the State stays the same throughout this whole process :]
document.location.href = "https://bsky.social/oauth/authorize?client_id=https://fedi.crowdedgames.group/oauth/client-metadata.json&request_uri=" + body.request_uri;
document.location.href = Website + "/oauth/authorize?client_id=https://fedi.crowdedgames.group/oauth/client-metadata.json&request_uri=" + body.request_uri;
}
export async function GainTokens() {
let WellKnown = await GetPDSWellKnown();
// 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) && Cookie.IsCookieReal(Cookie.BlueskyPKCEVerifier) && !(Cookie.IsCookieReal(Cookie.BlueskyAccessToken))) {
if ((document.location.href.split("state=").length > 1 && document.location.href.split("iss=").length > 1 && document.location.href.split("code=").length > 1) && localStorage.getItem(Variables.BlueskyPKCEVerifier) != null && localStorage.getItem(Variables.BlueskyAccessToken) == null) {
// Create varaibles, be aware of waits because of internet.
let DPoP = await ClientDPoPToken("POST", WellKnown.token_endpoint);
let code = document.location.href.split("code=")[1];
// Authentication
let cookie = await Cookie.GetCookie(Cookie.BlueskyPKCEVerifier);
let Auth = await AuthRequest(WellKnown.token_endpoint, code, DPoP, cookie);
let Var = await localStorage.getItem(Variables.BlueskyPKCEVerifier);
let Auth = await AuthRequest(WellKnown.token_endpoint, code, DPoP, Var);
// Save the tokens and be done
Cookie.InputCookie(Cookie.BlueskyAccessToken, Auth.access_token);
Cookie.InputCookie(Cookie.BlueskyRefreshToken, Auth.refresh_token);
localStorage.setItem(Variables.BlueskyAccessToken, Auth.access_token);
localStorage.setItem(Variables.BlueskyRefreshToken, Auth.refresh_token);
// That long string just gets the payload
// aud = PDS server we are communicating with; sub = user DID
localStorage.setItem(Variables.BlueskyPDS, "https://" + KJUR.jws.JWS.readSafeJSONString(b64utoutf8(localStorage.getItem(Variables.BlueskyAccessToken).split(".")[1])).aud.split(":")[2]);
localStorage.setItem(Variables.BlueskyDID, KJUR.jws.JWS.readSafeJSONString(b64utoutf8(localStorage.getItem(Variables.BlueskyAccessToken).split(".")[1])).sub);
}
}
@ -213,18 +237,18 @@ export async function RefreshTokens() {
// Create varaibles, be aware of waits because of internet.
let DPoP = await ClientDPoPToken("POST", WellKnown.token_endpoint);
// Token refresh
let cookie = await Cookie.GetCookie(Cookie.BlueskyRefreshToken);
let Auth = ReauthRequest(WellKnown.token_endpoint, cookie, DPoP);
let Var = await localStorage.getItem(Variables.BlueskyRefreshToken);
let Auth = ReauthRequest(WellKnown.token_endpoint, Var, DPoP);
let body = await Auth.then((response) => response.json());
let header = await Auth.then((response) => response.headers.get("dpop-nonce"));
if (body.hasOwnProperty("error_description") && body.error_description.includes("DPoP nonce mismatch")) {
await Cookie.InputCookie(Cookie.BlueskyNonce, header);
localStorage.setItem(Variables.BlueskyNonce, header);
DPoP = await ClientDPoPToken("POST", WellKnown.token_endpoint);
let body = await ReauthRequest(WellKnown.token_endpoint, cookie, DPoP).then((response) => response.json());
body = await ReauthRequest(WellKnown.token_endpoint, Var, DPoP).then((response) => response.json());
}
// Save the tokens and be done
Cookie.InputCookie(Cookie.BlueskyAccessToken, body.access_token);
Cookie.InputCookie(Cookie.BlueskyRefreshToken, body.refresh_token);
localStorage.setItem(Variables.BlueskyAccessToken, body.access_token);
localStorage.setItem(Variables.BlueskyRefreshToken, body.refresh_token);
}
// Stolen from elsewhere.

View file

@ -1,65 +0,0 @@
// STRINGS TODO: make sure to seperate stuff that a user will want to input: BlueskyAppName, BlueskyPDSName.
// Mastodon
export const MastodonWebsite = "mastodon_website";
export const MastodonClientID = "mastodon_client_id";
export const MastodonClientSecret = "mastodon_client_secret";
export const MastodonAccessToken = "mastodon_access_token";
export const MastodonTokenType = "mastodon_token_type";
// Bluesky
export const BlueskyApp = "https://bsky.app";
export const BlueskyPDS = "https://bsky.social";
export const BlueskyPKCEVerifier = "bluesky_pkce_verifier";
export const BlueskyPKCEChallenge = "bluesky_pkce_challenge";
export const BlueskyPublicKey = "bluesky_public_key";
export const BlueskyPrivateKey = "bluesky_private_key";
export const BlueskyNonce = "bluesky_nonce";
export const BlueskyAccessToken = "bluesky_access_token";
export const BlueskyRefreshToken = "bluesky_refresh_token";
// Tumblr
export const TumblrWebsiteName = "https://www.tumblr.com";
// FUNCTIONS
// Get the cookie from cookie storage.
export function GetCookie(CookieName = "") {
// Check if you put in nothing.
if (CookieName == 0) {
console.error("Where is the cookie name? Returning nothing...");
return "";
}
// Get the cookie.
let Cookie = document.cookie.split("; ").find((row) => row.startsWith(CookieName + "="))?.split("=");
// If the cookie doesn't exist...
if (Cookie == undefined || Cookie.length == 1) {
console.log("Cookie not found. Returning nothing...");
return "";
} else {
return Cookie[1];
}
}
// Check if a cookie is real (as in the value isn't nonexistant).
export function IsCookieReal(CookieName = "") {
let Cookie = GetCookie(CookieName);
if (Cookie.length == 0) {
return false;
}
return true;
}
// Remove the cookie.
export function ExpireCookie(CookieName = "") {
document.cookie = CookieName + "=nothing;samesite=strict;path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT;";
return;
}
// Add a new cookie (or change it's value).
export function InputCookie(CookieName = "", Value = "") {
if (Value == 0 || CookieName == 0) {
console.error("You forgot to put in a value. Stopping...");
return;
}
document.cookie = CookieName + "=" + Value + ";samesite=strict;path=/;expires=Fri, 31 Dec 9999 23:59:59 GMT;"
return;
}

View file

@ -1,10 +1,10 @@
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";
export const Scopes = "read write follow push";
// Gets the public timeline.
export async function GetPublicTimeline(Local = false, Remote = false, Website) {
// Cookies can be found in `setting.js`
// Variables can be found in `setting.js`
let Timeline;
if (Local == true && Remote == true) {
console.error("Don't set both Local and Remote timelines to true.");
@ -28,10 +28,10 @@ export async function GetPublicTimeline(Local = false, Remote = false, Website)
export async function GetFavorites() {
let Favorites;
// Check for a token.
if (Cookie.IsCookieReal(Cookie.MastodonAccessToken)) {
let Website = Cookie.MastodonWebsite;
// Get the varaibles that are stored in cookies.
Favorites = await fetch(Website + "/api/v1/favourites", {method: "GET", headers: {"Authorization": Cookie.GetCookie(Cookie.MastodonTokenType) + " " + Cookie.GetCookie(Cookie.MastodonAccessToken)}})
if (localStorage.getItem(Variables.MastodonAccessToken) != null) {
let Website = Variables.MastodonWebsite;
// Get the varaibles that are stored in localStorage.
Favorites = await fetch(Website + "/api/v1/favourites", {method: "GET", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}})
.then((response) => response.json());
}
return Favorites;
@ -41,10 +41,10 @@ export async function GetFavorites() {
export async function GetBookmarks() {
let Bookmarks;
// Check for a token.
if (Cookie.IsCookieReal(Cookie.MastodonAccessToken)) {
let Website = Cookie.GetCookie(Cookie.MastodonWebsite);
// Get the varaibles that are stored in cookies.
Bookmarks = await fetch(Website + "/api/v1/bookmarks", {method: "GET", headers: {"Authorization": Cookie.GetCookie(Cookie.MastodonTokenType) + " " + Cookie.GetCookie(Cookie.MastodonAccessToken)}})
if (localStorage.getItem(Variables.MastodonAccessToken) != null) {
let Website = localStorage.getItem(Variables.MastodonWebsite);
// Get the varaibles that are stored in Variables.
Bookmarks = await fetch(Website + "/api/v1/bookmarks", {method: "GET", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}})
.then((response) => response.json());
}
return Bookmarks;
@ -54,21 +54,23 @@ export async function GetBookmarks() {
export async function GetNotifications() {
let Notifications;
// Check for a token.
if (Cookie.IsCookieReal(Cookie.MastodonAccessToken)) {
let Website = Cookie.GetCookie(Cookie.MastodonWebsite);
// Get the varaibles that are stored in cookies and then input it.
Notifications = await fetch(Website + "/api/v1/notifications", {method: "GET", headers: {"Authorization": Cookie.GetCookie(Cookie.MastodonTokenType) + " " + Cookie.GetCookie(Cookie.MastodonAccessToken)}})
if (localStorage.getItem(Variables.MastodonAccessToken) != null) {
let Website = localStorage.getItem(Variables.MastodonWebsite);
// Get the varaibles that are stored in Variables and then input it.
Notifications = await fetch(Website + "/api/v1/notifications", {method: "GET", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}})
.then((response) => response.json());
}
return Notifications;
}
// Make a status
export async function CreateStatus(Text) {
export async function CreateStatus(Text, Visibility = "public") {
// Stolen from StackOverflow
Text = Text.replace(/(?:\r|\n|\r\n)/g, '<br>');
// Check for a token
if (Cookie.IsCookieReal(Cookie.MastodonAccessToken)) {
let Website = Cookie.MastodonWebsiteCookie;
return await fetch(Website + "/api/v1/statuses?status=" + Text , {method: "POST", headers: {"Authorization": Cookie.GetCookie(Cookie.MastodonTokenType) + " " + Cookie.GetCookie(Cookie.MastodonAccessToken)}})
if (localStorage.getItem(Variables.MastodonAccessToken) != null) {
let Website = localStorage.getItem(Variables.MastodonWebsite);
return await fetch(Website + "/api/v1/statuses?status=" + Text + "&visibility=" + Visibility, {method: "POST", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}})
.then((response) => response.json());
}
}
@ -84,13 +86,13 @@ export async function HandleAuthentication(Website) {
Website = "https://" + Website;
}
// Save the website
Cookie.InputCookie(Cookie.MastodonWebsite, Website);
localStorage.setItem(Variables.MastodonWebsite, Website);
// Registering the app.
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.
Cookie.InputCookie(Cookie.MastodonClientID, InstanceData.client_id);
Cookie.InputCookie(Cookie.MastodonClientSecret, InstanceData.client_secret);
// Save the client stuff as Variables.
localStorage.setItem(Variables.MastodonClientID, InstanceData.client_id);
localStorage.setItem(Variables.MastodonClientSecret, InstanceData.client_secret);
// Now authenticate the app.
document.location.href = Website + "/oauth/authorize?client_id=" + InstanceData.client_id + "&redirect_uri=" + document.location.href + "&response_type=code&scope=" + Scopes;
}
@ -98,15 +100,15 @@ export async function HandleAuthentication(Website) {
// This specific functino goes after HandleAuthentication for when login happens.
export async function GainToken() {
// check if you both have a code and have a current authentication.
if (document.location.href.split("code=").length > 1 && Cookie.IsCookieReal(Cookie.MastodonClientID) && !(Cookie.IsCookieReal(Cookie.MastodonAccessToken))) {
if (document.location.href.split("code=").length > 1 && localStorage.getItem(Variables.MastodonClientID) != null && localStorage.getItem(Variables.MastodonAccessToken) == null) {
// Get some vars.
let code = document.location.href.split("code=")[1];
let Website = Cookie.GetCookie(Cookie.MastodonWebsite);
let Website = localStorage.getItem(Variables.MastodonWebsite);
// Authenticate.
let AuthenticationToken = await fetch(Website + "/oauth/token?client_id=" + Cookie.GetCookie(Cookie.MastodonClientID) + "&client_secret=" + Cookie.GetCookie(Cookie.MastodonClientSecret) + "&redirect_uri=" + document.location.href + "&grant_type=authorization_code&code=" + code, {method: "POST"})
let AuthenticationToken = await fetch(Website + "/oauth/token?client_id=" + localStorage.getItem(Variables.MastodonClientID) + "&client_secret=" + localStorage.getItem(Variables.MastodonClientSecret) + "&redirect_uri=" + document.location.href + "&grant_type=authorization_code&code=" + code, {method: "POST"})
.then((response) => response.json());
// Cookify These.
Cookie.InputCookie(Cookie.MastodonAccessToken, AuthenticationToken.access_token);
Cookie.InputCookie(Cookie.MastodonTokenType, AuthenticationToken.token_type);
localStorage.setItem(Variables.MastodonAccessToken, AuthenticationToken.access_token);
localStorage.setItem(Variables.MastodonTokenType, AuthenticationToken.token_type);
}
}

View file

@ -1 +1 @@
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";

24
JS/Variables.js Normal file
View file

@ -0,0 +1,24 @@
// STRINGS TODO: make sure to seperate stuff that a user will want to input: BlueskyPDSName.
// Mastodon
export const MastodonWebsite = "mastodon_website";
export const MastodonClientID = "mastodon_client_id";
export const MastodonClientSecret = "mastodon_client_secret";
export const MastodonAccessToken = "mastodon_access_token";
export const MastodonTokenType = "mastodon_token_type";
// Bluesky
export const BlueskyPDS = "bluesky_pds";
export const BlueskyDID = "bluesky_did";
export const BlueskyPKCEVerifier = "bluesky_pkce_verifier";
export const BlueskyPKCEChallenge = "bluesky_pkce_challenge";
export const BlueskyPublicKey = "bluesky_public_key";
export const BlueskyPrivateKey = "bluesky_private_key";
export const BlueskyNonce = "bluesky_nonce";
export const BlueskyAccessToken = "bluesky_access_token";
export const BlueskyRefreshToken = "bluesky_refresh_token";
// Tumblr
export const TumblrWebsiteName = "https://www.tumblr.com";
// WARNING: Research suggests that cookies are very unsecue.
// Every Fetch request (http or https) sends these cookies. That's bad!

View file

@ -1,7 +1,7 @@
import * as MastodonAPI from "./MastodonAPI.js";
import * as BlueskyAPI from "./BlueskyAPI.js";
import * as TumblrAPI from "./TumblrAPI.js";
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";
// GLOBAL VARS
// fuck you. I see why website developers use divs so fucking often.
@ -104,14 +104,14 @@ ArrowsButton[0].onclick = (event) => {
// MastodonAPI integration
async function PosterContainerUpdate() {
// Cookies for the public timelines
let LocalCookie = Cookie.GetCookie("Local");
var LocalTrue = (LocalCookie === "true");
let RemoteCookie = Cookie.GetCookie("Remote");
var RemoteTrue = (RemoteCookie === "true");
let Website = Cookie.GetCookie(Cookie.MastodonWebsite);
// Variables for the public timelines
let LocalVar = localStorage.getItem("Local");
var LocalTrue = (LocalVar === "true");
let RemoteVar = localStorage.getItem("Remote");
var RemoteTrue = (RemoteVar === "true");
let Website = localStorage.getItem(Variables.MastodonWebsite);
if (!(Cookie.IsCookieReal(Cookie.MastodonWebsite))) {
if (localStorage.getItem(Variables.MastodonWebsite) == null) {
Website = "https://wetdry.world";
}

View file

@ -1,7 +1,7 @@
import * as MastodonAPI from "./MastodonAPI.js";
import * as BlueskyAPI from "./BlueskyAPI.js";
import * as TumblrAPI from "./TumblrAPI.js";
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";
// Below is the thing it populates if you login.
async function PopulateFavorites() {

View file

@ -1,11 +1,12 @@
import * as MastodonAPI from "./MastodonAPI.js";
import * as BlueskyAPI from "./BlueskyAPI.js";
import * as TumblrAPI from "./TumblrAPI.js";
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";
// Elements.
let PostButton = document.getElementsByClassName("button")[0];
let InputArea = document.getElementsByClassName("text")[0];
let PostButton = document.getElementsByClassName("Button")[0];
let VisibilityDropdown = document.getElementsByClassName("PostVisibility")[0];
let InputArea = document.getElementsByClassName("Text")[0];
// Clicking the beeg POST button.
PostButton.onclick = (event) => {
@ -14,14 +15,56 @@ PostButton.onclick = (event) => {
async function Post() {
let Text = InputArea.value;
let Visible = VisibilityDropdown.value;
// don't do anything if there is no value
if (Text == "") {
return;
}
// Mastodon posting.
if (Cookie.IsCookieReal(Cookie.MastodonAccessToken)) {
MastodonAPI.CreateStatus(Text);
if (localStorage.getItem(Variables.MastodonAccessToken) != null) {
let TempVisible;
switch(Visible) {
case "Public":
TempVisible = "public";
break;
case "Quiet":
TempVisible = "unlisted";
break;
case "Friend":
TempVisible = "private";
break;
case "Private":
TempVisible = "direct";
break;
}
MastodonAPI.CreateStatus(Text, TempVisible);
}
// Bluesky posting.
if (Cookie.IsCookieReal(Cookie.BlueskyAccessToken)) {
let DID = await BlueskyAPI.GetBlueskyDID("https://woodear.us-west.host.bsky.network", "crowdedgames.group");
BlueskyAPI.CreatePost("https://woodear.us-west.host.bsky.network", DID.did, Text);
if (localStorage.getItem(Variables.BlueskyAccessToken) != null) {
let TempVisible;
switch(Visible) {
case "Public":
TempVisible = undefined;
break;
case "Quiet":
TempVisible = undefined;
break;
case "Friend":
TempVisible = [{"$type": "app.bsky.feed.threadgate#followingRule"}, {"$type": "app.bsky.feed.threadgate#followerRule"}];
break;
case "Private":
TempVisible = [];
break;
}
let Post = await BlueskyAPI.CreatePost(localStorage.getItem(Variables.BlueskyDID), Text);
console.log(Post);
let ThreadGate = await BlueskyAPI.SetThreadGate(localStorage.getItem(Variables.BlueskyDID), Post.uri, TempVisible);
console.log(ThreadGate);
}
InputArea.value = "";
}
// Check if you can interact with the textbox
if (localStorage.getItem(Variables.MastodonAccessToken) == null && localStorage.getItem(Variables.BlueskyAccessToken) == null) {
InputArea.disabled = true;
}

View file

@ -1,7 +1,7 @@
import * as MastodonAPI from "./MastodonAPI.js";
import * as BlueskyAPI from "./BlueskyAPI.js";
import * as TumblrAPI from "./TumblrAPI.js";
import * as Cookie from "./Cookies.js";
import * as Variables from "./Variables.js";
// Settings buttons
let LocalButton = document.getElementsByClassName("Local")[0];
@ -19,20 +19,20 @@ let Origin = location.origin + "/HTML/setting.html"
// Change weather the timelines are public or remote
LocalButton.onclick = (event) => {
// Toggle the cookie
if (Cookie.IsCookieReal("Local")) {
Cookie.ExpireCookie("Local");
// Toggle the Variable
if (localStorage.getItem("Local") != null) {
localStorage.removeItem("Local");
} else {
Cookie.InputCookie("Local", "true");
localStorage.setItem("Local", "true");
}
}
RemoteButton.onclick = (event) => {
// Toggle the cookie
if (Cookie.IsCookieReal("Romote")) {
Cookie.ExpireCookie("Remote");
// Toggle the Variable
if (localStorage.getItem("Remote") != null) {
localStorage.removeItem("Remote");
} else {
Cookie.InputCookie("Remote", "true");
localStorage.setItem("Remote", "true");
}
}
@ -47,10 +47,11 @@ MastodonLoginButton.onclick = (event) => {
// Logout
MastodonLogoutButton.onclick = (event) => {
Cookie.ExpireCookie(Cookie.MastodonClientID);
Cookie.ExpireCookie(Cookie.MastodonClientSecret);
Cookie.ExpireCookie(Cookie.MastodonAccessToken);
Cookie.ExpireCookie(Cookie.MastodonTokenType);
localStorage.removeItem(Variables.MastodonClientID);
localStorage.removeItem(Variables.MastodonClientSecret);
localStorage.removeItem(Variables.MastodonAccessToken);
localStorage.removeItem(Variables.MastodonTokenType);
localStorage.removeItem(Variables.MastodonWebsite);
document.location.href = Origin;
}
@ -58,36 +59,39 @@ MastodonLogoutButton.onclick = (event) => {
// Login
BlueskyLoginButton.onclick = (event) => {
if (BlueskyWebInput.value != "") {
BlueskyAPI.HandleAuthorization();
let text = BlueskyWebInput.value
BlueskyAPI.HandleAuthorization(text);
}
}
// Logout
BlueskyLogoutButton.onclick = (event) => {
Cookie.ExpireCookie(Cookie.BlueskyPKCEVerifier);
Cookie.ExpireCookie(Cookie.BlueskyPKCEChallenge);
Cookie.ExpireCookie(Cookie.BlueskyNonce);
Cookie.ExpireCookie(Cookie.BlueskyAccessToken);
Cookie.ExpireCookie(Cookie.BlueskyRefreshToken);
Cookie.ExpireCookie(Cookie.BlueskyPublicKey);
Cookie.ExpireCookie(Cookie.BlueskyPrivateKey);
localStorage.removeItem(Variables.BlueskyPDS);
localStorage.removeItem(Variables.BlueskyDID);
localStorage.removeItem(Variables.BlueskyPKCEVerifier);
localStorage.removeItem(Variables.BlueskyPKCEChallenge);
localStorage.removeItem(Variables.BlueskyNonce);
localStorage.removeItem(Variables.BlueskyAccessToken);
localStorage.removeItem(Variables.BlueskyRefreshToken);
localStorage.removeItem(Variables.BlueskyPublicKey);
localStorage.removeItem(Variables.BlueskyPrivateKey);
document.location.href = Origin;
}
// if an access token is found, login.
async function CheckLogin() {
// Check for a mastodon token.
if (Cookie.IsCookieReal(Cookie.MastodonAccessToken)) {
if (localStorage.getItem(Variables.MastodonAccessToken) != null) {
// Swap the buttons
MastodonLoginButton.remove();
MastodonWebInput.remove();
MastodonLogoutButton.setAttribute("style", "");
} else {
// Auto log in
await MastodonAPI.GainToken(Cookie.MastodonWebsite);
await MastodonAPI.GainToken(Variables.MastodonWebsite);
}
// Check for a bluesky token.
if (Cookie.IsCookieReal(Cookie.BlueskyAccessToken)) {
if (localStorage.getItem(Variables.BlueskyAccessToken) != null) {
// Swap the buttons
BlueskyLoginButton.remove();
BlueskyWebInput.remove();