-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1720a29
commit d371abb
Showing
4 changed files
with
233 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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@:%_+.~#?&//=]*)/, | ||
|
@@ -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, | ||
|
@@ -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", | ||
|
@@ -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("", ""); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |