parent
89e2c54d3e
commit
9b52f641cb
11 changed files with 226 additions and 186 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
120
JS/BlueskyAPI.js
120
JS/BlueskyAPI.js
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
import * as Cookie from "./Cookies.js";
|
||||
import * as Variables from "./Variables.js";
|
||||
|
|
24
JS/Variables.js
Normal file
24
JS/Variables.js
Normal 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!
|
16
JS/index.js
16
JS/index.js
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
59
JS/post.js
59
JS/post.js
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue