Skip to content

Commit

Permalink
allow key-user association in KeyManager (implements #5)
Browse files Browse the repository at this point in the history
  • Loading branch information
SammCheese committed Apr 26, 2023
1 parent 08eeb65 commit f2e5fd4
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 35 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"discordID": "372148345894076416",
"github": "SammCheese"
},
"version": "1.4.2",
"version": "1.4.3",
"updater": {
"type": "github",
"id": "SammCheese/RepluggedPGP"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "repluggedpgp",
"version": "1.4.2",
"version": "1.4.3",
"description": "Encrypt, Sign and Decrypt messages with the power of GPG",
"engines": {
"node": ">=14.0.0"
Expand Down Expand Up @@ -32,7 +32,7 @@
"eslint-plugin-react": "^7.31.10",
"openpgp": "^5.5.0",
"prettier": "^2.8.1",
"replugged": "4.2.4",
"replugged": "4.2.6",
"typescript": "^4.8.4"
},
"dependencies": {
Expand Down
14 changes: 7 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/components/AddKey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function AddKey(props: any) {
</Text.Eyebrow>
<Divider style={{ marginBottom: "15px", marginTop: "15px" }} />
<Text style={{ marginBottom: "5px" }}>User ID: {info.user.userID}</Text>
<Text style={{ marginBottom: "5px" }}>comment: {info.user.comment || "No Comment"}</Text>
<Text style={{ marginBottom: "5px" }}>Comment: {info.user.comment || "No Comment"}</Text>
<Text style={{ marginBottom: "5px" }}>Created: {info?.created.toString()}</Text>
<Divider style={{ marginBottom: "15px", marginTop: "15px" }}></Divider>
<Text markdown={true} selectable={true}>
Expand Down
27 changes: 10 additions & 17 deletions src/components/KeyManager.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { common, components } from "replugged";
import { PGPSettings, getKeyUserInfo } from "../utils";
import { PGPSettings, getKey, getKeyUserInfo } from "../utils";
import { UserIDPacket } from "openpgp";
import { buildKeyViewer } from "./KeyViewer";

const { React } = common;
const { closeModal, openModal } = common.modal;
Expand All @@ -14,19 +15,6 @@ interface KeyCardType {
userID: string;
}

/*function KeyDetails(props: any) {
return (
<Modal.ModalRoot>
<Modal.ModalHeader>
<Text.H1>Key Details</Text.H1>
</Modal.ModalHeader>
<Modal.ModalContent>
<Text> Balls</Text>
</Modal.ModalContent>
</Modal.ModalRoot>
);
}*/

function KeyCard(props: KeyCardType) {
const [userID, setUserData] = React.useState<UserIDPacket | null>();

Expand All @@ -47,12 +35,17 @@ function KeyCard(props: KeyCardType) {
marginLeft: "auto",
flexDirection: "row",
}}>
{/*<Button
<Button
style={{ marginRight: "7px" }}
look={Button.Looks.LINK}
onClick={() => openModal((props) => <KeyDetails {...props} />)}>
onClick={async () =>
buildKeyViewer({
keyInfo: await getKey(props.publicKey),
pubKey: props.publicKey,
})
}>
View
</Button>*/}
</Button>
<Button
onClick={() => {
const keys = PGPSettings.get("savedPubKeys", []);
Expand Down
63 changes: 63 additions & 0 deletions src/components/KeyViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { common, components } from "replugged";
import { KeyInfo } from "../repluggedpgp";
import { PGPSettings, associateUserWithKey, pgpFormat } from "../utils";

const { Button, Modal, Text, Divider, TextInput } = components;
const {
React,
modal: { closeModal, openModal },
} = common;

let modalKey: any;

function KeyViewer(props: any) {
const settingsIndex = PGPSettings.get("savedPubKeys", [])[
PGPSettings.get("savedPubKeys", []).findIndex((e) => e.publicKey.includes(props.pubKey))
];
const [associatedUser, setAssociatedUser] = React.useState(settingsIndex.userID);

const info: KeyInfo = {
created: props.keyInfo.keyPacket.created,
user: {
name: props.keyInfo.users[0].userID?.name,
email: props.keyInfo.users[0].userID?.email,
comment: props.keyInfo.users[0].userID?.comment,
userID: props.keyInfo.users[0].userID?.userID,
},
};

return (
<Modal.ModalRoot {...props}>
<Modal.ModalHeader>
<Text.H1>Key Viewer</Text.H1>
</Modal.ModalHeader>
<Modal.ModalContent>
<Text.Eyebrow style={{ marginTop: "10px" }}>Key Details for {info.user.name}</Text.Eyebrow>
<Divider style={{ marginBottom: "15px", marginTop: "15px" }} />
<Text style={{ marginBottom: "5px" }}>User ID: {info.user.userID}</Text>
<Text style={{ marginBottom: "5px" }}>Comment: {info.user.comment || "No Comment"}</Text>
<Text style={{ marginBottom: "5px" }}>Created: {info?.created.toString()}</Text>
<Divider style={{ marginBottom: "15px", marginTop: "15px" }} />
<Text.Eyebrow>Associate with User</Text.Eyebrow>
<TextInput
placeholder="372148345894076416"
value={associatedUser}
onChange={(e) => {
setAssociatedUser(e);
associateUserWithKey(props.pubKey, e);
}}></TextInput>
<Divider style={{ marginBottom: "15px", marginTop: "15px" }} />
<Text markdown={true} selectable={true}>
{pgpFormat(props.pubKey)}
</Text>
</Modal.ModalContent>
<Modal.ModalFooter>
<Button onClick={() => closeModal(modalKey)}>Close</Button>
</Modal.ModalFooter>
</Modal.ModalRoot>
);
}

export function buildKeyViewer(key: any): any {
modalKey = openModal((props: any) => <KeyViewer {...props} {...key} />);
}
16 changes: 15 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injector, common } from "replugged";
import {
PGPSettings,
calculateRecipients,
decryptMessage,
encryptMessage,
getKey,
Expand All @@ -21,6 +22,8 @@ import { DiscordMessage, RPGPWindow } from "./repluggedpgp";
import { buildAddKeyModal } from "./components/AddKey";
import { del } from "idb-keyval";

const { channels, messages } = common;

const injector = new Injector();

export async function start(): Promise<void> {
Expand Down Expand Up @@ -103,7 +106,18 @@ async function injectSendMessage(): Promise<void> {
injector.instead(common.messages, "sendMessage", async (args, fn) => {
const { signingActive, encryptionActive, asFile, onlyOnce } = PGPSettings.all();

if (encryptionActive) args[1].content = await encryptMessage(args[1].content, signingActive);
if (encryptionActive) {
let recipients = [];
const DM = channels.getChannel(args[0])?.recipients;
const Reply = args[3]?.messageReference;
// Also includes groupchats
if (DM) recipients = DM;
if (Reply?.channel_id && Reply?.message_id)
recipients = [messages.getMessage(Reply.channel_id, Reply.message_id).author.id];

const expectedRecipients = await calculateRecipients(recipients);
args[1].content = await encryptMessage(args[1].content, expectedRecipients, signingActive);
}

if (signingActive && !encryptionActive) args[1].content = await signMessage(args[1].content);

Expand Down
48 changes: 42 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,16 @@ async function tryMigrateSettings(): Promise<void> {
if (typeof element === "string") return { publicKey: element, userID: "" };
return element;
});
console.log(newSettings);
PGPSettings.set("savedPubKeys", newSettings);
}

// eslint-disable-next-line @typescript-eslint/require-await
export async function associateUserWithKey(key: string, userID: string): Promise<void> {
const keys = PGPSettings.get("savedPubKeys", []);
const newSettings = keys.map((elem) => {
if (elem.publicKey.includes(key)) elem.userID = userID;
return elem;
});
PGPSettings.set("savedPubKeys", newSettings);
}

Expand Down Expand Up @@ -142,18 +151,40 @@ export async function verifyMessage(ctMessage: string): Promise<string> {
return sigVerification;
}

export async function encryptMessage(message: string, sign?: boolean): Promise<string> {
const recipients = await buildRecipientSelection();
const publicKeys = await Promise.all(recipients.map((armoredKey) => pgp.readKey({ armoredKey })));

export async function encryptMessage(
message: string,
recipients: string[],
sign?: boolean,
): Promise<string> {
return await pgp.encrypt({
message: await pgp.createMessage({ text: message }),
encryptionKeys: publicKeys,
encryptionKeys: recipients,
// eslint-disable-next-line no-undefined
signingKeys: sign ? await getPrivateKey() : undefined,
});
}

export async function calculateRecipients(expectedRecipients: string[] = []): Promise<string[]> {
const keys = PGPSettings.get("savedPubKeys", []);

let recipients: Array<string | undefined>;

if (expectedRecipients.length === 0) {
recipients = await buildRecipientSelection();
} else {
recipients = expectedRecipients.map((userID) => {
const key = keys.find((e) => e.userID === userID);
return key ? key.publicKey : "";
});

if (recipients.every((r) => r === "")) {
recipients = await buildRecipientSelection();
}
}

return await Promise.all(recipients.map((armoredKey) => pgp.readKey({ armoredKey })));
}

export async function decryptMessage(message: string): Promise<decryptMessageType | undefined> {
const readMessage = await pgp.readMessage({ armoredMessage: message });
const key = await getPrivateKey();
Expand Down Expand Up @@ -198,6 +229,11 @@ export async function parseMessageFileContent(url: string): Promise<string> {
});
}

export function fetchChannelAndCompare(channel: string, userID: string): boolean {
const sentInChannel = channels.getChannel(channel);
return sentInChannel?.recipients.includes(userID);
}

export function sendAsFile(message: string): void {
addFile({
file: {
Expand Down

0 comments on commit f2e5fd4

Please sign in to comment.