Skip to content

Commit

Permalink
cleaning up some code
Browse files Browse the repository at this point in the history
  • Loading branch information
SammCheese committed Jan 2, 2023
1 parent 1720a29 commit d371abb
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 89 deletions.
2 changes: 1 addition & 1 deletion src/components/EncryptionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function EncModal(props: ModalProps) {
let [password, setPassword] = React.useState("password");
let [DontUseCover, setDontUseCover] = React.useState(false);

const valid = secret && DontUseCover ? true : cover && /\w \w/.test(cover);
const valid = secret && (DontUseCover || (cover && /\w \w/.test(cover)));

return (
<Modal.ModalRoot {...props}>
Expand Down
101 changes: 13 additions & 88 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,16 @@
import { common } from "replugged";

import { Indicator } from "./assets/indicator";
import { popoverIcon } from "./assets/popoverIcon";
import { chatbarLock } from "./assets/chatbarLock";
import { initEncModal } from "./components/EncryptionModal";
import { buildDecModal, initDecModal } from "./components/DecryptionModal";

import { cleanupEmbed, getEmbed, updateMessage } from "./utils";

const getStegCloak: Promise<StegCloakImport> = import(
// @ts-expect-error SHUT UP
"https://unpkg.com/[email protected].0/index.js"
"https://unpkg.com/[email protected].1/index.js"
);

// TYPES

type Constructor<StegCloak> = new (encrypt: boolean, useHmac: boolean) => Promise<StegCloak>;

interface StegCloak {
hide: (secret: string, password: string, cover: string) => string;
reveal: (secret: string, password: string) => string;
}

interface StegCloakImport {
default: Constructor<StegCloak>;
}

interface DiscordEmbed {
title: string;
type: string;
description: string;
url?: string;
timestamp?: EpochTimeStamp;
color?: number;
footer?: object;
image?: object;
thumbnail?: object;
video?: object;
provider?: object;
author?: object;
}

// CONSTANTS

const EMBED_URL = "https://embed.sammcheese.net";
const INV_DETECTION = new RegExp(/( \u200c|\u200d |[\u2060-\u2064])[^\u200b]/);
const URL_DETECTION = new RegExp(
/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
Expand All @@ -60,7 +29,7 @@ export async function start(): Promise<void> {
await initEncModal();

// Register the Message Receiver
// @ts-expect-error We are adding to Window
// @ts-expect-error adding to window
window.invisiblechat = {
popoverIcon,
INV_DETECTION,
Expand All @@ -71,50 +40,17 @@ export async function start(): Promise<void> {
}

// Grab the data from the above Plantext Patches
function receiver(message: unknown): void {
function receiver(message: DiscordMessage): void {
void buildDecModal({ message });
}

// Gets the Embed of a Link
async function getEmbed(url: URL): Promise<DiscordEmbed> {
// Timeout after 5 seconds
const controller = new AbortController();
const _timeout = setTimeout(() => controller.abort(), 5000);

const options = {
signal: controller.signal,
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
url,
}),
};

const rawRes = await fetch(EMBED_URL, options);
return await rawRes.json();
}

export function removeEmbed(message: unknown): void {
// @ts-expect-error not typed
for (let embed in message.embeds) {
// @ts-expect-error not typed
if (message.embeds[embed]?.footer?.text.includes("c0dine and Sammy!")) {
// @ts-expect-error not typed
message.embeds.splice(embed, 1);
}
}
updateMessage(message);
}

export async function buildEmbed(message: unknown, revealed: string): Promise<void> {
const urlCheck = revealed.match(URL_DETECTION) || [];
export async function buildEmbed(message: DiscordMessage, revealed: string): Promise<void> {
const urlCheck = revealed.match(URL_DETECTION)!;

let attachment: DiscordEmbed;
if (urlCheck[0]) attachment = await getEmbed(new URL(urlCheck[0]));
if (!urlCheck) attachment = await getEmbed(new URL(urlCheck[0]));

let embed = {
let embed: DiscordEmbed = {
type: "rich",
title: "Decrypted Message",
color: "0x45f5f5",
Expand All @@ -124,32 +60,21 @@ export async function buildEmbed(message: unknown, revealed: string): Promise<vo
},
};

// @ts-expect-error no type
message.embeds = message.embeds.map((embed: rawDiscordEmbed) => cleanupEmbed(embed));
if (attachment!) message.embeds.push(attachment);
message.embeds.push(embed);
// @ts-expect-error no type
if (attachment) message.embeds.push(attachment);
updateMessage(message);
return Promise.resolve();
}

function updateMessage(message: unknown): void {
// @ts-expect-error no type
common.fluxDispatcher.dispatch({
type: "MESSAGE_UPDATE",
message,
});
}

export function stop(): void {}

export function encrypt(secret: string, password: string, cover: string): string {
// Add Identifier unicode to secret (\u200b)
// Appending \u200b to the secret
// eslint-disable-next-line no-irregular-whitespace
return steggo.hide(`${secret}​`, password, cover);
}

export function decrypt(secret: string, password: string): string {
// Remove the Indicator when revealing
// Removing the \u200b indicator
// eslint-disable-next-line no-irregular-whitespace
return steggo.reveal(secret, password).replace("​", "");
}
104 changes: 104 additions & 0 deletions src/invisiblechat.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* eslint-disable @typescript-eslint/naming-convention */
type Constructor<StegCloak> = new (encrypt: boolean, useHmac: boolean) => Promise<StegCloak>;

interface StegCloak {
hide: (secret: string, password: string, cover: string) => string;
reveal: (secret: string, password: string) => string;
}

interface StegCloakImport {
default: Constructor<StegCloak>;
}

interface DiscordMedia {
url: string;
proxy_url?: string;
height?: number;
width?: number;
}

interface rawDiscordMedia extends Omit<DiscordMedia, "proxy_url"> {
proxyURL: string;
}

interface DiscordEmbed {
title: string;
reference_id?: string;
type: "rich" | "image" | "video" | "gifv" | "article" | "link";
description: string;
url?: string;
timestamp?: ISO8601;
color?: string | number;
footer?: {
text: string;
icon_url?: string;
proxy_icon_url?: string;
};
image?: DiscordMedia;
thumbnail?: DiscordMedia;
video?: DiscordMedia;
provider?: {
name?: string;
url?: string;
};
author?: {
name: string;
url?: string;
icon_url?: string;
proxy_icon_url?: string;
};
fields?: [
{
name: string;
value: string;
inline?: boolean;
},
];
}

interface rawDiscordEmbed {
id: number;
type: "rich" | "image" | "video" | "gifv" | "article" | "link";
rawTitle: string;
rawDescription: string;
referenceId: string;
url?: string;
color?: string | number;
timestamp: ISO8601;
image?: rawDiscordMedia;
thumbnail?: rawDiscordMedia;
video?: rawDiscordMedia;
footer?: {
text: string;
iconURL?: string;
iconProxyURL?: string;
};
author?: {
name: string;
url?: string;
iconURL?: string;
iconProxyURL: string;
};
provider?: {
name?: string;
url?: string;
};
fields?: [
{
rawName: string;
rawValue: string;
inline?: boolean;
},
];
}

interface ISO8601 {
milliseconds: () => ISO8601;
_isAMomentObject: boolean;
}

interface DiscordMessage {
channel: object;
content: string;
embeds: Arrays<DiscordEmbed>;
}
115 changes: 115 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* eslint-disable no-undefined */
/* eslint-disable @typescript-eslint/naming-convention */

import { common } from "replugged";

const EMBED_URL = "https://embed.sammcheese.net";

export function cleanupEmbed(embed: rawDiscordEmbed): DiscordEmbed {
/* backported code from MLV2 rewrite */
// @ts-expect-error Already Cleaned
if (!embed.id) return embed;
// @ts-expect-error Empty Array
const retEmbed: DiscordEmbed = {};
if (typeof embed.rawTitle === "string") retEmbed.title = embed.rawTitle;
if (typeof embed.rawDescription === "string") retEmbed.description = embed.rawDescription;
if (typeof embed.referenceId !== "undefined") retEmbed.reference_id = embed.referenceId;
if (typeof embed.color === "string") retEmbed.color = embed.color;
if (typeof embed.type !== "undefined") retEmbed.type = embed.type;
if (typeof embed.url !== "undefined") retEmbed.url = embed.url;
if (typeof embed.provider === "object")
retEmbed.provider = { name: embed.provider.name, url: embed.provider.url };
if (typeof embed.footer === "object")
retEmbed.footer = {
text: embed.footer.text,
icon_url: embed.footer.iconURL,
proxy_icon_url: embed.footer.iconProxyURL,
};
if (typeof embed.author === "object")
retEmbed.author = {
name: embed.author.name,
url: embed.author.url,
icon_url: embed.author.iconURL,
proxy_icon_url: embed.author.iconProxyURL,
};
if (typeof embed.timestamp === "object" && embed.timestamp._isAMomentObject)
retEmbed.timestamp = embed.timestamp.milliseconds();
if (typeof embed.thumbnail === "object") {
if (
typeof embed.thumbnail.proxyURL === "string" ||
(typeof embed.thumbnail.url === "string" && !embed.thumbnail.url.endsWith("?format=jpeg"))
) {
retEmbed.thumbnail = {
url: embed.thumbnail.url,
proxy_url:
typeof embed.thumbnail.proxyURL === "string"
? embed.thumbnail.proxyURL.split("?format")[0]
: undefined,
width: embed.thumbnail.width,
height: embed.thumbnail.height,
};
}
}
if (typeof embed.image === "object") {
retEmbed.image = {
url: embed.image.url,
proxy_url: embed.image.proxyURL,
width: embed.image.width,
height: embed.image.height,
};
}
if (typeof embed.video === "object") {
retEmbed.video = {
url: embed.video.url,
proxy_url: embed.video.proxyURL,
width: embed.video.width,
height: embed.video.height,
};
}
if (Array.isArray(embed.fields) && embed.fields.length) {
// @ts-expect-error ???
retEmbed.fields = embed.fields.map((e) => ({
name: e.rawName,
value: e.rawValue,
inline: e.inline,
}));
}
return retEmbed;
}

export function updateMessage(message: unknown): void {
// @ts-expect-error no type
common.fluxDispatcher.dispatch({
type: "MESSAGE_UPDATE",
message,
});
}

export function removeEmbed(message: DiscordMessage): void {
for (let embed in message.embeds) {
if (message.embeds[embed]?.footer?.text.includes("c0dine and Sammy!")) {
message.embeds.splice(embed, 1);
}
}
updateMessage(message);
}

export async function getEmbed(url: URL): Promise<DiscordEmbed> {
// Timeout after 5 seconds
const controller = new AbortController();
const _timeout = setTimeout(() => controller.abort(), 5000);

const options = {
signal: controller.signal,
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
url,
}),
};

const rawRes = await fetch(EMBED_URL, options);
return await rawRes.json();
}

0 comments on commit d371abb

Please sign in to comment.