mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 20:49:16 +00:00
more webapp profile refactor
This commit is contained in:
parent
91c5a88096
commit
4cba051a5d
@ -79,3 +79,107 @@ export function decryptTopicSubject(subject, contentKey) {
|
|||||||
return JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
return JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertPem(pem) {
|
||||||
|
var lines = pem.split('\n');
|
||||||
|
var encoded = '';
|
||||||
|
for(var i = 0;i < lines.length;i++){
|
||||||
|
if (lines[i].trim().length > 0 &&
|
||||||
|
lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
|
||||||
|
lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
|
||||||
|
lines[i].indexOf('-BEGIN PUBLIC KEY-') < 0 &&
|
||||||
|
lines[i].indexOf('-END PUBLIC KEY-') < 0 &&
|
||||||
|
lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
|
||||||
|
lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
|
||||||
|
encoded += lines[i].trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encoded
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function generateSeal(password) {
|
||||||
|
|
||||||
|
// generate key to encrypt private key
|
||||||
|
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const aes = CryptoJS.PBKDF2(password, salt, {
|
||||||
|
keySize: 256 / 32,
|
||||||
|
iterations: 1024,
|
||||||
|
});
|
||||||
|
|
||||||
|
// generate rsa key for sealing channel, delay for activity indicators
|
||||||
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
|
const crypto = new JSEncrypt({ default_key_size: 2048 });
|
||||||
|
crypto.getKey();
|
||||||
|
|
||||||
|
// encrypt private key
|
||||||
|
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const privateKey = convertPem(crypto.getPrivateKey());
|
||||||
|
const enc = CryptoJS.AES.encrypt(privateKey, aes, { iv: iv });
|
||||||
|
const publicKey = convertPem(crypto.getPublicKey());
|
||||||
|
|
||||||
|
// update account
|
||||||
|
const seal = {
|
||||||
|
passwordSalt: salt.toString(),
|
||||||
|
privateKeyIv: iv.toString(),
|
||||||
|
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
||||||
|
publicKey: publicKey,
|
||||||
|
}
|
||||||
|
const sealKey = {
|
||||||
|
public: publicKey,
|
||||||
|
private: privateKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
return { seal, sealKey };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unlockSeal(seal, password) {
|
||||||
|
|
||||||
|
// generate key to encrypt private key
|
||||||
|
const salt = CryptoJS.enc.Hex.parse(seal.passwordSalt);
|
||||||
|
const aes = CryptoJS.PBKDF2(password, salt, {
|
||||||
|
keySize: 256 / 32,
|
||||||
|
iterations: 1024,
|
||||||
|
});
|
||||||
|
|
||||||
|
// decrypt private key
|
||||||
|
const iv = CryptoJS.enc.Hex.parse(seal.privateKeyIv);
|
||||||
|
const enc = CryptoJS.enc.Base64.parse(seal.privateKeyEncrypted)
|
||||||
|
|
||||||
|
let cipherParams = CryptoJS.lib.CipherParams.create({
|
||||||
|
ciphertext: enc,
|
||||||
|
iv: iv
|
||||||
|
});
|
||||||
|
const dec = CryptoJS.AES.decrypt(cipherParams, aes, { iv: iv });
|
||||||
|
const privateKey = dec.toString(CryptoJS.enc.Utf8)
|
||||||
|
|
||||||
|
// store ke
|
||||||
|
const sealKey = {
|
||||||
|
public: seal.publicKey,
|
||||||
|
private: privateKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
return sealKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateSeal(seal, sealKey, password) {
|
||||||
|
|
||||||
|
// generate key to encrypt private key
|
||||||
|
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const aes = CryptoJS.PBKDF2(password, salt, {
|
||||||
|
keySize: 256 / 32,
|
||||||
|
iterations: 1024,
|
||||||
|
});
|
||||||
|
|
||||||
|
// encrypt private key
|
||||||
|
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const enc = CryptoJS.AES.encrypt(sealKey.private, aes, { iv: iv });
|
||||||
|
|
||||||
|
// update account
|
||||||
|
const updated = {
|
||||||
|
passwordSalt: salt.toString(),
|
||||||
|
privateKeyIv: iv.toString(),
|
||||||
|
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
||||||
|
publicKey: seal.publicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
return { seal: updated, sealKey };
|
||||||
|
}
|
||||||
|
@ -28,7 +28,7 @@ export function useProfileContext() {
|
|||||||
const token = access.current;
|
const token = access.current;
|
||||||
const revision = curRevision.current;
|
const revision = curRevision.current;
|
||||||
const identity = await getProfile(access.current);
|
const identity = await getProfile(access.current);
|
||||||
const imageUrl = identity.image ? getProfileImageUrl(token, revision) : null;
|
const imageUrl = identity.image ? getProfileImageUrl(token, identity.revision) : null;
|
||||||
setRevision.current = revision;
|
setRevision.current = revision;
|
||||||
updateState({ offsync: false, identity, imageUrl });
|
updateState({ offsync: false, identity, imageUrl });
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ export function Profile({ closeProfile }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ state.init && state.display !== 'xlarge' && (
|
{ state.display !== 'xlarge' && (
|
||||||
<div className="account">
|
<div className="account">
|
||||||
<div className="section">Account Settings</div>
|
<div className="section">Account Settings</div>
|
||||||
<div className="controls">
|
<div className="controls">
|
||||||
|
@ -173,8 +173,6 @@ export const ProfileWrapper = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-top: 1px solid ${Colors.divider};
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
width: 75%;
|
width: 75%;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { AccountAccessWrapper, SealModal, EditFooter } from './AccountAccess.styled';
|
import { AccountAccessWrapper, SealModal, EditFooter } from './AccountAccess.styled';
|
||||||
import { useAccountAccess } from './useAccountAccess.hook';
|
import { useAccountAccess } from './useAccountAccess.hook';
|
||||||
import { AccountLogin } from './accountLogin/AccountLogin';
|
import { Button, Modal, Switch, Form, Input } from 'antd';
|
||||||
import { Button, Modal, Switch, Input } from 'antd';
|
import { SettingOutlined, UserOutlined, LockOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
import { SettingOutlined, LockOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
export function AccountAccess() {
|
export function AccountAccess() {
|
||||||
|
|
||||||
|
const [ modal, modalContext ] = Modal.useModal();
|
||||||
const { state, actions } = useAccountAccess();
|
const { state, actions } = useAccountAccess();
|
||||||
|
|
||||||
const saveSeal = async () => {
|
const saveSeal = async () => {
|
||||||
@ -15,7 +15,7 @@ export function AccountAccess() {
|
|||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
Modal.error({
|
modal.error({
|
||||||
title: 'Failed to Set Sealing Key',
|
title: 'Failed to Set Sealing Key',
|
||||||
comment: 'Please try again.',
|
comment: 'Please try again.',
|
||||||
});
|
});
|
||||||
@ -28,7 +28,7 @@ export function AccountAccess() {
|
|||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
Modal.error({
|
modal.error({
|
||||||
title: 'Update Registry Failed',
|
title: 'Update Registry Failed',
|
||||||
content: 'Please try again.',
|
content: 'Please try again.',
|
||||||
});
|
});
|
||||||
@ -42,7 +42,7 @@ export function AccountAccess() {
|
|||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
Modal.error({
|
modal.error({
|
||||||
title: 'Failed to Save',
|
title: 'Failed to Save',
|
||||||
comment: 'Please try again.',
|
comment: 'Please try again.',
|
||||||
});
|
});
|
||||||
@ -51,7 +51,7 @@ export function AccountAccess() {
|
|||||||
|
|
||||||
const editLoginFooter = (
|
const editLoginFooter = (
|
||||||
<EditFooter>
|
<EditFooter>
|
||||||
<div class="select"></div>
|
<div className="select"></div>
|
||||||
<Button key="back" onClick={actions.clearEditLogin}>Cancel</Button>
|
<Button key="back" onClick={actions.clearEditLogin}>Cancel</Button>
|
||||||
<Button key="save" type="primary" onClick={saveLogin} disabled={!actions.canSaveLogin()} loading={state.busy}>Save</Button>
|
<Button key="save" type="primary" onClick={saveLogin} disabled={!actions.canSaveLogin()} loading={state.busy}>Save</Button>
|
||||||
</EditFooter>
|
</EditFooter>
|
||||||
@ -59,7 +59,7 @@ export function AccountAccess() {
|
|||||||
|
|
||||||
const editSealFooter = (
|
const editSealFooter = (
|
||||||
<EditFooter>
|
<EditFooter>
|
||||||
<div class="select"></div>
|
<div className="select"></div>
|
||||||
<Button key="back" onClick={actions.clearEditSeal}>Cancel</Button>
|
<Button key="back" onClick={actions.clearEditSeal}>Cancel</Button>
|
||||||
{ state.sealMode === 'enabled' && (
|
{ state.sealMode === 'enabled' && (
|
||||||
<Button key="save" type="primary" onClick={saveSeal} loading={state.busy}>Forget</Button>
|
<Button key="save" type="primary" onClick={saveSeal} loading={state.busy}>Forget</Button>
|
||||||
@ -75,50 +75,51 @@ export function AccountAccess() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AccountAccessWrapper>
|
<AccountAccessWrapper>
|
||||||
<div class="switch">
|
{ modalContext }
|
||||||
|
<div className="switch">
|
||||||
<Switch size="small" checked={state.searchable} onChange={enable => saveSearchable(enable)} />
|
<Switch size="small" checked={state.searchable} onChange={enable => saveSearchable(enable)} />
|
||||||
<div class="switchLabel">Visible in Registry </div>
|
<div className="switchLabel">Visible in Registry </div>
|
||||||
</div>
|
</div>
|
||||||
<div class="link" onClick={actions.setEditSeal}>
|
<div className="link" onClick={actions.setEditSeal}>
|
||||||
<SettingOutlined />
|
<SettingOutlined />
|
||||||
<div class="label">Sealed Topics</div>
|
<div className="label">Sealed Topics</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="link" onClick={actions.setEditLogin}>
|
<div className="link" onClick={actions.setEditLogin}>
|
||||||
<LockOutlined />
|
<LockOutlined />
|
||||||
<div class="label">Change Login</div>
|
<div className="label">Change Login</div>
|
||||||
</div>
|
</div>
|
||||||
<Modal title="Topic Sealing Key" centered visible={state.editSeal} footer={editSealFooter} onCancel={actions.clearEditSeal}>
|
<Modal title="Topic Sealing Key" centered visible={state.editSeal} footer={editSealFooter} onCancel={actions.clearEditSeal}>
|
||||||
<SealModal>
|
<SealModal>
|
||||||
<div class="switch">
|
<div className="switch">
|
||||||
<Switch size="small" checked={state.sealEnabled} onChange={enable => actions.enableSeal(enable)} />
|
<Switch size="small" checked={state.sealEnabled} onChange={enable => actions.enableSeal(enable)} />
|
||||||
<div class="switchLabel">Enable Sealed Topics</div>
|
<div className="switchLabel">Enable Sealed Topics</div>
|
||||||
</div>
|
</div>
|
||||||
{ (state.sealMode === 'updating' || state.sealMode === 'enabling') && (
|
{ (state.sealMode === 'updating' || state.sealMode === 'enabling') && (
|
||||||
<div class="sealPassword">
|
<div className="sealPassword">
|
||||||
<Input.Password placeholder="New Password" spellCheck="false" onChange={(e) => actions.setSealPassword(e.target.value)}
|
<Input.Password placeholder="New Password" spellCheck="false" onChange={(e) => actions.setSealPassword(e.target.value)}
|
||||||
autocomplete="new-password" prefix={<LockOutlined />} />
|
autocomplete="new-password" prefix={<LockOutlined />} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ (state.sealMode === 'updating' || state.sealMode === 'enabling') && (
|
{ (state.sealMode === 'updating' || state.sealMode === 'enabling') && (
|
||||||
<div class="sealPassword">
|
<div className="sealPassword">
|
||||||
<Input.Password placeholder="Confirm Password" spellCheck="false" onChange={(e) => actions.setSealConfirm(e.target.value)}
|
<Input.Password placeholder="Confirm Password" spellCheck="false" onChange={(e) => actions.setSealConfirm(e.target.value)}
|
||||||
autocomplete="new-password" prefix={<LockOutlined />} />
|
autocomplete="new-password" prefix={<LockOutlined />} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ state.sealMode === 'disabling' && (
|
{ state.sealMode === 'disabling' && (
|
||||||
<div class="sealPassword">
|
<div className="sealPassword">
|
||||||
<Input placeholder="Type 'delete' to remove key" spellCheck="false" onChange={(e) => actions.setSealDelete(e.target.value)}
|
<Input placeholder="Type 'delete' to remove key" spellCheck="false" onChange={(e) => actions.setSealDelete(e.target.value)}
|
||||||
prefix={<ExclamationCircleOutlined />} />
|
prefix={<ExclamationCircleOutlined />} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ state.sealMode === 'enabled' && (
|
{ state.sealMode === 'enabled' && (
|
||||||
<div class="sealPassword" onClick={() => actions.updateSeal()}>
|
<div className="sealPassword" onClick={() => actions.updateSeal()}>
|
||||||
<Input.Password defaultValue="xxxxxxxxxx" disabled={true} prefix={<LockOutlined />} />
|
<Input.Password defaultValue="xxxxxxxxxx" disabled={true} prefix={<LockOutlined />} />
|
||||||
<div class="editPassword" />
|
<div className="editPassword" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ state.sealMode === 'unlocking' && (
|
{ state.sealMode === 'unlocking' && (
|
||||||
<div class="sealPassword">
|
<div className="sealPassword">
|
||||||
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setSealUnlock(e.target.value)}
|
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setSealUnlock(e.target.value)}
|
||||||
prefix={<LockOutlined />} />
|
prefix={<LockOutlined />} />
|
||||||
</div>
|
</div>
|
||||||
@ -127,7 +128,22 @@ export function AccountAccess() {
|
|||||||
</Modal>
|
</Modal>
|
||||||
<Modal title="Account Login" centered visible={state.editLogin} footer={editLoginFooter}
|
<Modal title="Account Login" centered visible={state.editLogin} footer={editLoginFooter}
|
||||||
onCancel={actions.clearEditLogin}>
|
onCancel={actions.clearEditLogin}>
|
||||||
<AccountLogin state={state} actions={actions} />
|
<Form name="basic" wrapperCol={{ span: 24, }}>
|
||||||
|
<Form.Item name="username" validateStatus={state.editStatus} help={state.editMessage}>
|
||||||
|
<Input placeholder="Username" spellCheck="false" onChange={(e) => actions.setEditHandle(e.target.value)}
|
||||||
|
defaultValue={state.editHandle} autocomplete="username" autocapitalize="none" prefix={<UserOutlined />} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="password">
|
||||||
|
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setEditPassword(e.target.value)}
|
||||||
|
autocomplete="new-password" prefix={<LockOutlined />} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="confirm">
|
||||||
|
<Input.Password placeholder="Confirm Password" spellCheck="false" onChange={(e) => actions.setEditConfirm(e.target.value)}
|
||||||
|
autocomplete="new-password" prefix={<LockOutlined />} />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
</AccountAccessWrapper>
|
</AccountAccessWrapper>
|
||||||
);
|
);
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import { Form, Input } from 'antd';
|
|
||||||
import { LockOutlined, UserOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
export function AccountLogin({ state, actions }) {
|
|
||||||
return (
|
|
||||||
<Form name="basic" wrapperCol={{ span: 24, }}>
|
|
||||||
<Form.Item name="username" validateStatus={state.editStatus} help={state.editMessage}>
|
|
||||||
<Input placeholder="Username" spellCheck="false" onChange={(e) => actions.setEditHandle(e.target.value)}
|
|
||||||
defaultValue={state.editHandle} autocomplete="username" autocapitalize="none" prefix={<UserOutlined />} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="password">
|
|
||||||
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setEditPassword(e.target.value)}
|
|
||||||
autocomplete="new-password" prefix={<LockOutlined />} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="confirm">
|
|
||||||
<Input.Password placeholder="Confirm Password" spellCheck="false" onChange={(e) => actions.setEditConfirm(e.target.value)}
|
|
||||||
autocomplete="new-password" prefix={<LockOutlined />} />
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
import { useRef, useState, useEffect, useContext } from 'react';
|
import { useRef, useState, useEffect, useContext } from 'react';
|
||||||
import { AccountContext } from 'context/AccountContext';
|
import { AccountContext } from 'context/AccountContext';
|
||||||
import { ProfileContext } from 'context/ProfileContext';
|
import { ProfileContext } from 'context/ProfileContext';
|
||||||
|
import { generateSeal, unlockSeal, updateSeal } from 'context/sealUtil';
|
||||||
import { getUsername } from 'api/getUsername';
|
import { getUsername } from 'api/getUsername';
|
||||||
import CryptoJS from 'crypto-js';
|
import CryptoJS from 'crypto-js';
|
||||||
import { JSEncrypt } from 'jsencrypt'
|
import { JSEncrypt } from 'jsencrypt'
|
||||||
@ -40,63 +41,18 @@ export function useAccountAccess() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (profile.state.identity?.guid) {
|
const { handle } = profile.state.identity;
|
||||||
const { handle } = profile.state.identity;
|
updateState({ handle, editHandle: handle });
|
||||||
updateState({ handle, editHandle: handle });
|
}, [profile.state]);
|
||||||
}
|
|
||||||
}, [profile]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (account?.state?.status) {
|
const { seal, sealKey, status } = account.state;
|
||||||
const { seal, sealKey, status } = account.state;
|
updateState({ searchable: status.searchable, seal, sealKey });
|
||||||
updateState({ searchable: status.searchable, seal, sealKey });
|
}, [account.state]);
|
||||||
}
|
|
||||||
}, [account]);
|
|
||||||
|
|
||||||
const convertPem = (pem) => {
|
|
||||||
var lines = pem.split('\n');
|
|
||||||
var encoded = '';
|
|
||||||
for(var i = 0;i < lines.length;i++){
|
|
||||||
if (lines[i].trim().length > 0 &&
|
|
||||||
lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
|
|
||||||
lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
|
|
||||||
lines[i].indexOf('-BEGIN PUBLIC KEY-') < 0 &&
|
|
||||||
lines[i].indexOf('-END PUBLIC KEY-') < 0 &&
|
|
||||||
lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
|
|
||||||
lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
|
|
||||||
encoded += lines[i].trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return encoded
|
|
||||||
};
|
|
||||||
|
|
||||||
const sealUnlock = async () => {
|
const sealUnlock = async () => {
|
||||||
|
const unlocked = unlockSeal(state.seal, state.sealUnlock);
|
||||||
// generate key to encrypt private key
|
await account.actions.unlockSeal(unlocked);
|
||||||
const salt = CryptoJS.enc.Hex.parse(state.seal.passwordSalt);
|
|
||||||
const aes = CryptoJS.PBKDF2(state.sealUnlock, salt, {
|
|
||||||
keySize: 256 / 32,
|
|
||||||
iterations: 1024,
|
|
||||||
});
|
|
||||||
|
|
||||||
// decrypt private key
|
|
||||||
const iv = CryptoJS.enc.Hex.parse(state.seal.privateKeyIv);
|
|
||||||
const enc = CryptoJS.enc.Base64.parse(state.seal.privateKeyEncrypted)
|
|
||||||
|
|
||||||
let cipherParams = CryptoJS.lib.CipherParams.create({
|
|
||||||
ciphertext: enc,
|
|
||||||
iv: iv
|
|
||||||
});
|
|
||||||
const dec = CryptoJS.AES.decrypt(cipherParams, aes, { iv: iv });
|
|
||||||
const privateKey = dec.toString(CryptoJS.enc.Utf8)
|
|
||||||
|
|
||||||
// store ke
|
|
||||||
const sealKey = {
|
|
||||||
public: state.seal.publicKey,
|
|
||||||
private: privateKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
await account.actions.unlockSeal(sealKey);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const sealForget = async () => {
|
const sealForget = async () => {
|
||||||
@ -104,37 +60,8 @@ export function useAccountAccess() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sealEnable = async () => {
|
const sealEnable = async () => {
|
||||||
|
const generated = await generateSeal(state.sealPassword);
|
||||||
// generate key to encrypt private key
|
await account.actions.setSeal(generated.seal, generated.sealKey);
|
||||||
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
|
||||||
const aes = CryptoJS.PBKDF2(state.sealPassword, salt, {
|
|
||||||
keySize: 256 / 32,
|
|
||||||
iterations: 1024,
|
|
||||||
});
|
|
||||||
|
|
||||||
// generate rsa key for sealing channel, delay for activity indicator
|
|
||||||
await new Promise(r => setTimeout(r, 1000));
|
|
||||||
const crypto = new JSEncrypt({ default_key_size: 2048 });
|
|
||||||
crypto.getKey();
|
|
||||||
|
|
||||||
// encrypt private key
|
|
||||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
|
||||||
const privateKey = convertPem(crypto.getPrivateKey());
|
|
||||||
const enc = CryptoJS.AES.encrypt(privateKey, aes, { iv: iv });
|
|
||||||
const publicKey = convertPem(crypto.getPublicKey());
|
|
||||||
|
|
||||||
// update account
|
|
||||||
const seal = {
|
|
||||||
passwordSalt: salt.toString(),
|
|
||||||
privateKeyIv: iv.toString(),
|
|
||||||
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
|
||||||
publicKey: publicKey,
|
|
||||||
}
|
|
||||||
const sealKey = {
|
|
||||||
public: publicKey,
|
|
||||||
private: privateKey,
|
|
||||||
}
|
|
||||||
await account.actions.setSeal(seal, sealKey);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const sealRemove = async () => {
|
const sealRemove = async () => {
|
||||||
@ -142,26 +69,8 @@ export function useAccountAccess() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sealUpdate = async () => {
|
const sealUpdate = async () => {
|
||||||
|
const updated = updateSeal(state.seal, state.sealKey, state.sealPassword);
|
||||||
// generate key to encrypt private key
|
await account.actions.updateSeal(state.seal);
|
||||||
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
|
||||||
const aes = CryptoJS.PBKDF2(state.sealPassword, salt, {
|
|
||||||
keySize: 256 / 32,
|
|
||||||
iterations: 1024,
|
|
||||||
});
|
|
||||||
|
|
||||||
// encrypt private key
|
|
||||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
|
||||||
const enc = CryptoJS.AES.encrypt(state.sealKey.private, aes, { iv: iv });
|
|
||||||
|
|
||||||
// update account
|
|
||||||
const seal = {
|
|
||||||
passwordSalt: salt.toString(),
|
|
||||||
privateKeyIv: iv.toString(),
|
|
||||||
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
|
||||||
publicKey: state.seal.publicKey,
|
|
||||||
}
|
|
||||||
await account.actions.updateSeal(seal);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isEnabled = () => {
|
const isEnabled = () => {
|
||||||
@ -296,18 +205,20 @@ export function useAccountAccess() {
|
|||||||
if (editHandle.toLowerCase() === state.handle.toLowerCase()) {
|
if (editHandle.toLowerCase() === state.handle.toLowerCase()) {
|
||||||
updateState({ checked: true, editStatus: 'success', editMessage: '' });
|
updateState({ checked: true, editStatus: 'success', editMessage: '' });
|
||||||
}
|
}
|
||||||
try {
|
else {
|
||||||
let valid = await getUsername(editHandle);
|
try {
|
||||||
if (valid) {
|
let valid = await getUsername(editHandle);
|
||||||
|
if (valid) {
|
||||||
|
updateState({ checked: true, editStatus: 'success', editMessage: '' });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updateState({ checked: true, editStatus: 'error', editMessage: 'Username is not available' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
updateState({ checked: true, editStatus: 'success', editMessage: '' });
|
updateState({ checked: true, editStatus: 'success', editMessage: '' });
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
updateState({ checked: true, editStatus: 'error', editMessage: 'Username is not available' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
console.log(err);
|
|
||||||
updateState({ checked: true, editStatus: 'success', editMessage: '' });
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
|
@ -18,10 +18,8 @@ export function useProfile() {
|
|||||||
editProfileImage: false,
|
editProfileImage: false,
|
||||||
editProfileDetails: false,
|
editProfileDetails: false,
|
||||||
clip: { w: 0, h: 0, x: 0, y: 0 },
|
clip: { w: 0, h: 0, x: 0, y: 0 },
|
||||||
|
|
||||||
crop: { x: 0, y: 0},
|
crop: { x: 0, y: 0},
|
||||||
zoom: 1,
|
zoom: 1,
|
||||||
|
|
||||||
busy: false,
|
busy: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -35,13 +33,11 @@ export function useProfile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (profile.state.identity.guid) {
|
const { node, name, handle, location, description, image, imageUrl } = profile.state.identity;
|
||||||
const { node, name, handle, location, description, image, imageUrl } = profile.state.identity;
|
let url = !image ? null : profile.state.imageUrl;
|
||||||
let url = !image ? null : profile.state.imageUrl;
|
let editImage = !image ? avatar : url;
|
||||||
let editImage = !image ? avatar : url;
|
updateState({ name, location, description, node, handle, url,
|
||||||
updateState({ name, location, description, node, handle, url,
|
editName: name, editLocation: location, editDescription: description, editHandle: handle, editImage });
|
||||||
editName: name, editLocation: location, editDescription: description, editHandle: handle, editImage });
|
|
||||||
}
|
|
||||||
}, [profile.state]);
|
}, [profile.state]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user