mirror of
https://github.com/morten-olsen/parcel.git
synced 2026-02-08 01:36:24 +01:00
chore: quality of life improvements (#449)
This commit is contained in:
@@ -1,5 +1,19 @@
|
||||
import React, { useState, useCallback, useContext, createContext, useEffect } from 'react';
|
||||
import { readMessage, readKey, decrypt as pgpDecrypt, readPrivateKeys, readPrivateKey, generateKey } from 'openpgp';
|
||||
import React, {
|
||||
useState,
|
||||
useCallback,
|
||||
useContext,
|
||||
createContext,
|
||||
useEffect,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import {
|
||||
readMessage,
|
||||
readKey,
|
||||
decrypt as pgpDecrypt,
|
||||
readPrivateKeys,
|
||||
readPrivateKey,
|
||||
generateKey,
|
||||
} from 'openpgp';
|
||||
import GithubContext from './Github';
|
||||
import FileType from '../types/File';
|
||||
import { createFile } from '../helpers/files';
|
||||
@@ -9,11 +23,15 @@ interface DecryptionContextType {
|
||||
privateKey: string | undefined;
|
||||
createKey: (name: string, email: string) => void;
|
||||
deleteKey: () => void;
|
||||
files: {[id: string]: FileType};
|
||||
files: { [id: string]: FileType };
|
||||
addFile: (file: File) => Promise<void>;
|
||||
deleteFile: (id: string) => void;
|
||||
}
|
||||
|
||||
type DecryptionProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const removeExtension = (name: string) => {
|
||||
const parts = name.split('.');
|
||||
parts.pop();
|
||||
@@ -24,21 +42,32 @@ const DecryptionContext = createContext<DecryptionContextType>({
|
||||
publicKey: undefined,
|
||||
privateKey: undefined,
|
||||
files: {},
|
||||
createKey: async () => { throw new Error('Not using provider'); },
|
||||
deleteKey: async () => { throw new Error('Not using provider'); },
|
||||
addFile: async () => { throw new Error('Not using provider'); },
|
||||
deleteFile: async () => { throw new Error('Not using provider'); },
|
||||
createKey: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
deleteKey: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
addFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
deleteFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
});
|
||||
|
||||
const decrypt = async (privateKey: string, keys: string[], content: string) => {
|
||||
const armoredKeys = await Promise.all(
|
||||
keys.map(key => readKey({ armoredKey: key })),
|
||||
keys.map((key) => readKey({ armoredKey: key }))
|
||||
);
|
||||
const message = await readMessage({ armoredMessage: content });
|
||||
const encrypted = await pgpDecrypt({
|
||||
message,
|
||||
decryptionKeys: await readPrivateKeys({ armoredKeys: privateKey }),
|
||||
verificationKeys: armoredKeys.reduce<any>((output, key: any) => [...output, ...key], []),
|
||||
verificationKeys: armoredKeys.reduce<any>(
|
||||
(output, key: any) => [...output, ...key],
|
||||
[]
|
||||
),
|
||||
});
|
||||
const { data } = encrypted;
|
||||
const blob = new Blob([data as any], {
|
||||
@@ -47,7 +76,7 @@ const decrypt = async (privateKey: string, keys: string[], content: string) => {
|
||||
return blob;
|
||||
};
|
||||
|
||||
const DecryptionProvider: React.FC = ({
|
||||
const DecryptionProvider: React.FC<DecryptionProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { keys } = useContext(GithubContext);
|
||||
@@ -55,12 +84,15 @@ const DecryptionProvider: React.FC = ({
|
||||
const [publicKey, setPublicKey] = useState<string | undefined>(undefined);
|
||||
const [files, setFiles] = useState<DecryptionContextType['files']>({});
|
||||
|
||||
const deleteFile = useCallback((id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
}, [files]);
|
||||
const deleteFile = useCallback(
|
||||
(id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
},
|
||||
[files]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const run = async () => {
|
||||
@@ -83,29 +115,34 @@ const DecryptionProvider: React.FC = ({
|
||||
|
||||
const createKey = async () => {
|
||||
const key = await generateKey({
|
||||
userIDs: [{ name: 'unknown unknown', email: 'unknown@unknown.foo'}],
|
||||
userIDs: [{ name: 'unknown unknown', email: 'unknown@unknown.foo' }],
|
||||
curve: 'ed25519',
|
||||
});
|
||||
|
||||
setPrivateKey(key.privateKey);
|
||||
setPublicKey(key.publicKey);
|
||||
localStorage.setItem('key', key.privateKey);
|
||||
}
|
||||
};
|
||||
|
||||
const addFile = useCallback(async (file: File) => {
|
||||
if (!keys || !privateKey) return;
|
||||
const addedFile = createFile(setFiles, removeExtension(file.name));
|
||||
const reader = new FileReader()
|
||||
const addFile = useCallback(
|
||||
async (file: File) => {
|
||||
if (!keys || !privateKey) {
|
||||
return;
|
||||
}
|
||||
const addedFile = createFile(setFiles, removeExtension(file.name));
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onabort = addedFile.setFailed,
|
||||
reader.onerror = addedFile.setFailed,
|
||||
reader.onload = () => {
|
||||
addedFile.setContent(
|
||||
decrypt(privateKey, keys, reader.result as string),
|
||||
);
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}, [keys, privateKey]);
|
||||
(reader.onabort = addedFile.setFailed),
|
||||
(reader.onerror = addedFile.setFailed),
|
||||
(reader.onload = () => {
|
||||
addedFile.setContent(
|
||||
decrypt(privateKey, keys, reader.result as string)
|
||||
);
|
||||
});
|
||||
reader.readAsText(file);
|
||||
},
|
||||
[keys, privateKey]
|
||||
);
|
||||
|
||||
return (
|
||||
<DecryptionContext.Provider
|
||||
@@ -124,8 +161,6 @@ const DecryptionProvider: React.FC = ({
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
DecryptionProvider,
|
||||
};
|
||||
export { DecryptionProvider };
|
||||
|
||||
export default DecryptionContext;;
|
||||
export default DecryptionContext;
|
||||
|
||||
@@ -1,31 +1,50 @@
|
||||
import React, { useState, useCallback, useContext, createContext } from 'react';
|
||||
import React, {
|
||||
useState,
|
||||
useCallback,
|
||||
useContext,
|
||||
createContext,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import * as openpgp from 'openpgp';
|
||||
import GithubContext from './Github';
|
||||
import { createFile } from '../helpers/files';
|
||||
import FileType from '../types/File';
|
||||
|
||||
interface EncryptionContextType {
|
||||
files: {[id: string]: FileType};
|
||||
files: { [id: string]: FileType };
|
||||
addFile: (file: File) => Promise<void>;
|
||||
addText: (text: string, name: string) => Promise<void>;
|
||||
deleteFile: (id: string) => void;
|
||||
}
|
||||
|
||||
type EncryptionProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const EncryptionContext = createContext<EncryptionContextType>({
|
||||
files: {},
|
||||
addFile: async () => { throw new Error('Not using provider'); },
|
||||
addText: async () => { throw new Error('Not using provider'); },
|
||||
deleteFile: async () => { throw new Error('Not using provider'); },
|
||||
addFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
addText: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
deleteFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
});
|
||||
|
||||
const encrypt = async (keys: string[], content: string) => {
|
||||
const armoredKeys = await Promise.all(
|
||||
keys.map(key => openpgp.readKeys({ armoredKeys: key })),
|
||||
keys.map((key) => openpgp.readKeys({ armoredKeys: key }))
|
||||
);
|
||||
const message = await openpgp.createMessage({ text: content });
|
||||
const encrypted = await openpgp.encrypt({
|
||||
message,
|
||||
encryptionKeys: armoredKeys.reduce<any>((output, key: any) => [...output, ...key], []),
|
||||
encryptionKeys: armoredKeys.reduce<any>(
|
||||
(output, key: any) => [...output, ...key],
|
||||
[]
|
||||
),
|
||||
});
|
||||
const data = encrypted;
|
||||
const blob = new Blob([data as any], {
|
||||
@@ -34,41 +53,50 @@ const encrypt = async (keys: string[], content: string) => {
|
||||
return blob;
|
||||
};
|
||||
|
||||
const EncryptionProvider: React.FC = ({
|
||||
const EncryptionProvider: React.FC<EncryptionProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { username, keys } = useContext(GithubContext);
|
||||
const [files, setFiles] = useState<EncryptionContextType['files']>({});
|
||||
|
||||
const deleteFile = useCallback((id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
}, [files]);
|
||||
const deleteFile = useCallback(
|
||||
(id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
},
|
||||
[files]
|
||||
);
|
||||
|
||||
const addFile = useCallback(async (file: File) => {
|
||||
if (!keys) return;
|
||||
const addedFile = createFile(setFiles, `${file.name}.acs`);
|
||||
const reader = new FileReader()
|
||||
const addFile = useCallback(
|
||||
async (file: File) => {
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
const addedFile = createFile(setFiles, `${file.name}.acs`);
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onabort = addedFile.setFailed,
|
||||
reader.onerror = addedFile.setFailed,
|
||||
reader.onload = () => {
|
||||
addedFile.setContent(
|
||||
encrypt(keys, reader.result as string),
|
||||
);
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}, [keys, username]);
|
||||
(reader.onabort = addedFile.setFailed),
|
||||
(reader.onerror = addedFile.setFailed),
|
||||
(reader.onload = () => {
|
||||
addedFile.setContent(encrypt(keys, reader.result as string));
|
||||
});
|
||||
reader.readAsText(file);
|
||||
},
|
||||
[keys, username]
|
||||
);
|
||||
|
||||
const addText = useCallback(async (text: string, name: string) => {
|
||||
if (!keys) return;
|
||||
const file = createFile(setFiles, `${name}.txt.asc`);
|
||||
file.setContent(
|
||||
encrypt(keys, text),
|
||||
);
|
||||
}, [keys, username]);
|
||||
const addText = useCallback(
|
||||
async (text: string, name: string) => {
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
const file = createFile(setFiles, `${name}.txt.asc`);
|
||||
file.setContent(encrypt(keys, text));
|
||||
},
|
||||
[keys, username]
|
||||
);
|
||||
|
||||
return (
|
||||
<EncryptionContext.Provider
|
||||
@@ -84,9 +112,6 @@ const EncryptionProvider: React.FC = ({
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
EncryptionProvider,
|
||||
};
|
||||
export { EncryptionProvider };
|
||||
|
||||
export default EncryptionContext;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { createContext } from 'react';
|
||||
import React, { createContext, ReactNode } from 'react';
|
||||
|
||||
declare var data: any;
|
||||
|
||||
@@ -7,19 +7,17 @@ interface GithubContextType {
|
||||
keys?: string[];
|
||||
}
|
||||
|
||||
type GithubProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const GithubContext = createContext<GithubContextType>(data);
|
||||
const GithubProvider: React.FC = ({
|
||||
children,
|
||||
}) => (
|
||||
<GithubContext.Provider
|
||||
value={{ ...data }}
|
||||
>
|
||||
const GithubProvider: React.FC<GithubProviderProps> = ({ children }) => (
|
||||
<GithubContext.Provider value={{ ...data }}>
|
||||
{children}
|
||||
</GithubContext.Provider>
|
||||
);
|
||||
|
||||
export {
|
||||
GithubProvider,
|
||||
};
|
||||
export { GithubProvider };
|
||||
|
||||
export default GithubContext;
|
||||
|
||||
Reference in New Issue
Block a user