mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-03-28 08:15:55 +00:00
Merge branch 'master' of https://github.com/Qortal/chrome-extension into error-messages
This commit is contained in:
commit
5f4666bf3a
6
package-lock.json
generated
6
package-lock.json
generated
@ -17,6 +17,7 @@
|
|||||||
"asmcrypto.js": "2.3.2",
|
"asmcrypto.js": "2.3.2",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"buffer": "6.0.3",
|
"buffer": "6.0.3",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"jssha": "3.3.1",
|
"jssha": "3.3.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
@ -3439,6 +3440,11 @@
|
|||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": "^10.12.0 || >=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||||
|
},
|
||||||
"node_modules/file-selector": {
|
"node_modules/file-selector": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"asmcrypto.js": "2.3.2",
|
"asmcrypto.js": "2.3.2",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"buffer": "6.0.3",
|
"buffer": "6.0.3",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"jssha": "3.3.1",
|
"jssha": "3.3.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
|
@ -62,6 +62,36 @@ document.addEventListener('qortalExtensionRequests', async (event) => {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if (type === 'REQUEST_OAUTH') {
|
||||||
|
const hostname = window.location.hostname
|
||||||
|
const res = await connection(hostname)
|
||||||
|
if(!res){
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "OAUTH", data: {
|
||||||
|
error: "Not authorized"
|
||||||
|
}, requestId }
|
||||||
|
}));
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage({ action: "oauth", payload: {
|
||||||
|
nodeBaseUrl: payload.nodeBaseUrl,
|
||||||
|
senderAddress: payload.senderAddress,
|
||||||
|
senderPublicKey: payload.senderPublicKey, timestamp: payload.timestamp
|
||||||
|
}}, (response) => {
|
||||||
|
if (response.error) {
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "OAUTH", data: {
|
||||||
|
error: response.error
|
||||||
|
}, requestId }
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// Include the requestId in the detail when dispatching the response
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "OAUTH", data: response, requestId }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (type === 'REQUEST_AUTHENTICATION') {
|
} else if (type === 'REQUEST_AUTHENTICATION') {
|
||||||
const hostname = window.location.hostname
|
const hostname = window.location.hostname
|
||||||
const res = await connection(hostname)
|
const res = await connection(hostname)
|
||||||
@ -148,3 +178,14 @@ document.addEventListener('qortalExtensionRequests', async (event) => {
|
|||||||
}
|
}
|
||||||
// Handle other request types as needed...
|
// Handle other request types as needed...
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||||
|
if (message.type === "LOGOUT") {
|
||||||
|
// Notify the web page
|
||||||
|
window.postMessage({
|
||||||
|
type: "LOGOUT",
|
||||||
|
from: 'qortal'
|
||||||
|
}, "*");
|
||||||
|
}
|
||||||
|
});
|
178
src/App.tsx
178
src/App.tsx
@ -53,7 +53,9 @@ type extStates =
|
|||||||
| "download-wallet"
|
| "download-wallet"
|
||||||
| "create-wallet"
|
| "create-wallet"
|
||||||
| "transfer-success-regular"
|
| "transfer-success-regular"
|
||||||
| "transfer-success-request";
|
| "transfer-success-request"
|
||||||
|
| "wallet-dropped"
|
||||||
|
;
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [extState, setExtstate] = useState<extStates>("not-authenticated");
|
const [extState, setExtstate] = useState<extStates>("not-authenticated");
|
||||||
@ -73,6 +75,8 @@ function App() {
|
|||||||
const [walletToBeDownloaded, setWalletToBeDownloaded] = useState<any>(null);
|
const [walletToBeDownloaded, setWalletToBeDownloaded] = useState<any>(null);
|
||||||
const [walletToBeDownloadedPassword, setWalletToBeDownloadedPassword] =
|
const [walletToBeDownloadedPassword, setWalletToBeDownloadedPassword] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
|
const [authenticatePassword, setAuthenticatePassword] =
|
||||||
|
useState<string>("");
|
||||||
const [sendqortState, setSendqortState] = useState<any>(null);
|
const [sendqortState, setSendqortState] = useState<any>(null);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||||
const [
|
const [
|
||||||
@ -81,7 +85,8 @@ function App() {
|
|||||||
] = useState<string>("");
|
] = useState<string>("");
|
||||||
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
|
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
|
const [walletToBeDecryptedError, setWalletToBeDecryptedError] =
|
||||||
|
useState<string>("");
|
||||||
const holdRefExtState = useRef<extStates>("not-authenticated")
|
const holdRefExtState = useRef<extStates>("not-authenticated")
|
||||||
useEffect(()=> {
|
useEffect(()=> {
|
||||||
if(extState){
|
if(extState){
|
||||||
@ -135,10 +140,10 @@ function App() {
|
|||||||
for (const field of requiredFields) {
|
for (const field of requiredFields) {
|
||||||
if (!(field in pf)) throw new Error(field + " not found in JSON");
|
if (!(field in pf)) throw new Error(field + " not found in JSON");
|
||||||
}
|
}
|
||||||
// setBackupjson(pf)
|
// storeWalletInfo(pf);
|
||||||
storeWalletInfo(pf);
|
|
||||||
setRawWallet(pf);
|
setRawWallet(pf);
|
||||||
setExtstate("authenticated");
|
// setExtstate("authenticated");
|
||||||
|
setExtstate("wallet-dropped");
|
||||||
setdecryptedWallet(null);
|
setdecryptedWallet(null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
@ -296,10 +301,10 @@ function App() {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!paymentPassword) {
|
// if (!paymentPassword) {
|
||||||
setSendPaymentError("Please enter your wallet password");
|
// setSendPaymentError("Please enter your wallet password");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
chrome.runtime.sendMessage(
|
chrome.runtime.sendMessage(
|
||||||
{
|
{
|
||||||
@ -351,7 +356,6 @@ function App() {
|
|||||||
// rawWalletRef.current = rawWallet
|
// rawWalletRef.current = rawWallet
|
||||||
// }, [rawWallet])
|
// }, [rawWallet])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
@ -447,18 +451,35 @@ function App() {
|
|||||||
crypto.kdfThreads,
|
crypto.kdfThreads,
|
||||||
() => {}
|
() => {}
|
||||||
);
|
);
|
||||||
setRawWallet(wallet);
|
chrome.runtime.sendMessage({ action: "decryptWallet", payload: {
|
||||||
storeWalletInfo(wallet);
|
password: walletToBeDownloadedPassword,
|
||||||
setWalletToBeDownloaded({
|
wallet
|
||||||
wallet,
|
} }, (response) => {
|
||||||
qortAddress: wallet.address0,
|
if (response && !response?.error) {
|
||||||
|
setRawWallet(wallet);
|
||||||
|
setWalletToBeDownloaded({
|
||||||
|
wallet,
|
||||||
|
qortAddress: wallet.address0,
|
||||||
|
});
|
||||||
|
chrome.runtime.sendMessage({ action: "userInfo" }, (response2) => {
|
||||||
|
setIsLoading(false)
|
||||||
|
if (response2 && !response2.error) {
|
||||||
|
setUserInfo(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
getBalanceFunc();
|
||||||
|
} else if(response?.error){
|
||||||
|
setIsLoading(false)
|
||||||
|
setWalletToBeDecryptedError(response.error)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setWalletToBeDownloadedError(error?.message);
|
setWalletToBeDownloadedError(error?.message);
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoutFunc = () => {
|
const logoutFunc = () => {
|
||||||
@ -505,6 +526,40 @@ function App() {
|
|||||||
setSendqortState(null);
|
setSendqortState(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const authenticateWallet = async()=> {
|
||||||
|
try {
|
||||||
|
setIsLoading(true)
|
||||||
|
setWalletToBeDecryptedError('')
|
||||||
|
await new Promise<void>((res)=> {
|
||||||
|
setTimeout(()=> {
|
||||||
|
res()
|
||||||
|
}, 250)
|
||||||
|
})
|
||||||
|
chrome.runtime.sendMessage({ action: "decryptWallet", payload: {
|
||||||
|
password: authenticatePassword,
|
||||||
|
wallet: rawWallet
|
||||||
|
} }, (response) => {
|
||||||
|
if (response && !response?.error) {
|
||||||
|
setAuthenticatePassword("");
|
||||||
|
setExtstate("authenticated");
|
||||||
|
setWalletToBeDecryptedError('')
|
||||||
|
chrome.runtime.sendMessage({ action: "userInfo" }, (response) => {
|
||||||
|
setIsLoading(false)
|
||||||
|
if (response && !response.error) {
|
||||||
|
setUserInfo(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
getBalanceFunc();
|
||||||
|
} else if(response?.error){
|
||||||
|
setIsLoading(false)
|
||||||
|
setWalletToBeDecryptedError(response.error)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setWalletToBeDecryptedError('Unable to authenticate. Wrong password')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContainer>
|
<AppContainer>
|
||||||
{extState === "not-authenticated" && (
|
{extState === "not-authenticated" && (
|
||||||
@ -802,7 +857,7 @@ function App() {
|
|||||||
>
|
>
|
||||||
{sendqortState?.amount} QORT
|
{sendqortState?.amount} QORT
|
||||||
</TextP>
|
</TextP>
|
||||||
<Spacer height="29px" />
|
{/* <Spacer height="29px" />
|
||||||
|
|
||||||
<CustomLabel htmlFor="standard-adornment-password">
|
<CustomLabel htmlFor="standard-adornment-password">
|
||||||
Confirm Wallet Password
|
Confirm Wallet Password
|
||||||
@ -812,7 +867,7 @@ function App() {
|
|||||||
id="standard-adornment-password"
|
id="standard-adornment-password"
|
||||||
value={paymentPassword}
|
value={paymentPassword}
|
||||||
onChange={(e) => setPaymentPassword(e.target.value)}
|
onChange={(e) => setPaymentPassword(e.target.value)}
|
||||||
/>
|
/> */}
|
||||||
<Spacer height="29px" />
|
<Spacer height="29px" />
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -945,6 +1000,85 @@ function App() {
|
|||||||
</CustomButton>
|
</CustomButton>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{rawWallet && extState === 'wallet-dropped' && (
|
||||||
|
<>
|
||||||
|
<Spacer height="22px" />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
width: "100%",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
paddingLeft: "22px",
|
||||||
|
boxSizing: "border-box",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
onClick={()=> {
|
||||||
|
setRawWallet(null);
|
||||||
|
setExtstate("not-authenticated");
|
||||||
|
}}
|
||||||
|
src={Return}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Spacer height="10px" />
|
||||||
|
<div className="image-container" style={{
|
||||||
|
width: '136px',
|
||||||
|
height: '154px'
|
||||||
|
}}>
|
||||||
|
<img src={Logo1} className="base-image" />
|
||||||
|
<img src={Logo1Dark} className="hover-image" />
|
||||||
|
</div>
|
||||||
|
<Spacer height="35px" />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "start",
|
||||||
|
lineHeight: "24px",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 600,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Authenticate
|
||||||
|
</TextP>
|
||||||
|
</Box>
|
||||||
|
<Spacer height="35px" />
|
||||||
|
|
||||||
|
<>
|
||||||
|
<CustomLabel htmlFor="standard-adornment-password">
|
||||||
|
Wallet Password
|
||||||
|
</CustomLabel>
|
||||||
|
<Spacer height="5px" />
|
||||||
|
<PasswordField
|
||||||
|
id="standard-adornment-password"
|
||||||
|
value={authenticatePassword}
|
||||||
|
onChange={(e) =>
|
||||||
|
setAuthenticatePassword(e.target.value)
|
||||||
|
}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
authenticateWallet();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
<CustomButton onClick={authenticateWallet} >
|
||||||
|
Authenticate
|
||||||
|
</CustomButton>
|
||||||
|
<Typography color="error">
|
||||||
|
{walletToBeDecryptedError}
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{extState === "download-wallet" && (
|
{extState === "download-wallet" && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="22px" />
|
<Spacer height="22px" />
|
||||||
@ -1010,7 +1144,7 @@ function App() {
|
|||||||
<CustomButton onClick={confirmPasswordToDownload}>
|
<CustomButton onClick={confirmPasswordToDownload}>
|
||||||
Confirm password
|
Confirm password
|
||||||
</CustomButton>
|
</CustomButton>
|
||||||
<Typography color="errror">
|
<Typography color="error">
|
||||||
{walletToBeDownloadedError}
|
{walletToBeDownloadedError}
|
||||||
</Typography>
|
</Typography>
|
||||||
</>
|
</>
|
||||||
@ -1095,7 +1229,7 @@ function App() {
|
|||||||
<CustomButton onClick={createAccountFunc}>
|
<CustomButton onClick={createAccountFunc}>
|
||||||
Create Account
|
Create Account
|
||||||
</CustomButton>
|
</CustomButton>
|
||||||
<Typography color="errror">
|
<Typography color="error">
|
||||||
{walletToBeDownloadedError}
|
{walletToBeDownloadedError}
|
||||||
</Typography>
|
</Typography>
|
||||||
</>
|
</>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import Base58 from "./deps/Base58";
|
import Base58 from "./deps/Base58";
|
||||||
import { createTransaction } from "./transactions/transactions";
|
import { createTransaction } from "./transactions/transactions";
|
||||||
|
import { decryptChatMessage } from "./utils/decryptChatMessage";
|
||||||
import { decryptStoredWallet } from "./utils/decryptWallet";
|
import { decryptStoredWallet } from "./utils/decryptWallet";
|
||||||
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
|
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
|
||||||
import { validateAddress } from "./utils/validateAddress";
|
import { validateAddress } from "./utils/validateAddress";
|
||||||
@ -18,9 +19,8 @@ export const walletVersion = 2;
|
|||||||
// List of your API endpoints
|
// List of your API endpoints
|
||||||
const apiEndpoints = [
|
const apiEndpoints = [
|
||||||
"https://api.qortal.org",
|
"https://api.qortal.org",
|
||||||
"https://webapi.qortal.online",
|
"https://api2.qortal.org",
|
||||||
"https://web-api.qortal.online",
|
"https://appnode.qortal.org",
|
||||||
"https://api.qortal.online",
|
|
||||||
"https://apinode.qortalnodes.live",
|
"https://apinode.qortalnodes.live",
|
||||||
"https://apinode1.qortalnodes.live",
|
"https://apinode1.qortalnodes.live",
|
||||||
"https://apinode2.qortalnodes.live",
|
"https://apinode2.qortalnodes.live",
|
||||||
@ -79,6 +79,15 @@ async function getAddressInfo(address) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getKeyPair() {
|
||||||
|
const res = await chrome.storage.local.get(["keyPair"]);
|
||||||
|
if (res?.keyPair) {
|
||||||
|
return res.keyPair;
|
||||||
|
} else {
|
||||||
|
throw new Error("Wallet not authenticated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getSaveWallet() {
|
async function getSaveWallet() {
|
||||||
const res = await chrome.storage.local.get(["walletInfo"]);
|
const res = await chrome.storage.local.get(["walletInfo"]);
|
||||||
if (res?.walletInfo) {
|
if (res?.walletInfo) {
|
||||||
@ -132,8 +141,10 @@ const processTransactionVersion2 = async (body: any, validApi: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const transaction = async ({ type, params, apiVersion, keyPair }: any, validApi) => {
|
const transaction = async (
|
||||||
|
{ type, params, apiVersion, keyPair }: any,
|
||||||
|
validApi
|
||||||
|
) => {
|
||||||
const tx = createTransaction(type, keyPair, params);
|
const tx = createTransaction(type, keyPair, params);
|
||||||
let res;
|
let res;
|
||||||
|
|
||||||
@ -155,20 +166,22 @@ const makeTransactionRequest = async (
|
|||||||
keyPair,
|
keyPair,
|
||||||
validApi
|
validApi
|
||||||
) => {
|
) => {
|
||||||
|
const myTxnrequest = await transaction(
|
||||||
const myTxnrequest = await transaction({
|
{
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
type: 2,
|
type: 2,
|
||||||
params: {
|
params: {
|
||||||
recipient: receiver,
|
recipient: receiver,
|
||||||
// recipientName: recipientName,
|
// recipientName: recipientName,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
lastReference: lastRef,
|
lastReference: lastRef,
|
||||||
fee: fee,
|
fee: fee,
|
||||||
|
},
|
||||||
|
apiVersion: 2,
|
||||||
|
keyPair,
|
||||||
},
|
},
|
||||||
apiVersion: 2,
|
validApi
|
||||||
keyPair,
|
);
|
||||||
}, validApi);
|
|
||||||
return myTxnrequest;
|
return myTxnrequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -214,18 +227,71 @@ async function getNameOrAddress(receiver) {
|
|||||||
if (!response?.ok) throw new Error("Cannot fetch name");
|
if (!response?.ok) throw new Error("Cannot fetch name");
|
||||||
return { error: "cannot validate address or name" };
|
return { error: "cannot validate address or name" };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error?.message || "cannot validate address or name")
|
throw new Error(error?.message || "cannot validate address or name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function sendCoin({ password, amount, receiver }) {
|
|
||||||
|
async function decryptWallet({password, wallet, walletVersion}) {
|
||||||
|
try {
|
||||||
|
const response = await decryptStoredWallet(password, wallet);
|
||||||
|
const wallet2 = new PhraseWallet(response, walletVersion);
|
||||||
|
const keyPair = wallet2._addresses[0].keyPair;
|
||||||
|
const toSave = {
|
||||||
|
privateKey: Base58.encode(keyPair.privateKey),
|
||||||
|
publicKey: Base58.encode(keyPair.publicKey)
|
||||||
|
}
|
||||||
|
const dataString = JSON.stringify(toSave)
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.local.set({ keyPair: dataString }, () => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
reject(new Error(chrome.runtime.lastError.message));
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.local.set({ walletInfo: wallet }, () => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
reject(new Error(chrome.runtime.lastError.message));
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log({error})
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendCoin({ password, amount, receiver }, skipConfirmPassword) {
|
||||||
try {
|
try {
|
||||||
const confirmReceiver = await getNameOrAddress(receiver);
|
const confirmReceiver = await getNameOrAddress(receiver);
|
||||||
if (confirmReceiver.error)
|
if (confirmReceiver.error)
|
||||||
throw new Error("Invalid receiver address or name");
|
throw new Error("Invalid receiver address or name");
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
const response = await decryptStoredWallet(password, wallet);
|
let keyPair = ''
|
||||||
|
if(skipConfirmPassword){
|
||||||
|
const resKeyPair = await getKeyPair()
|
||||||
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
|
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
|
keyPair = {
|
||||||
|
privateKey: uint8PrivateKey,
|
||||||
|
publicKey: uint8PublicKey
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const response = await decryptStoredWallet(password, wallet);
|
||||||
const wallet2 = new PhraseWallet(response, walletVersion);
|
const wallet2 = new PhraseWallet(response, walletVersion);
|
||||||
|
|
||||||
|
keyPair = wallet2._addresses[0].keyPair
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const lastRef = await getLastRef();
|
const lastRef = await getLastRef();
|
||||||
const fee = await sendQortFee();
|
const fee = await sendQortFee();
|
||||||
const validApi = await findUsableApi();
|
const validApi = await findUsableApi();
|
||||||
@ -235,15 +301,79 @@ async function sendCoin({ password, amount, receiver }) {
|
|||||||
lastRef,
|
lastRef,
|
||||||
amount,
|
amount,
|
||||||
fee,
|
fee,
|
||||||
wallet2._addresses[0].keyPair,
|
keyPair,
|
||||||
validApi
|
validApi
|
||||||
);
|
);
|
||||||
return {res, validApi};
|
return { res, validApi };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error.message);
|
throw new Error(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchMessages(apiCall) {
|
||||||
|
let retryDelay = 2000; // Start with a 2-second delay
|
||||||
|
const maxDuration = 360000; // Maximum duration set to 6 minutes
|
||||||
|
const startTime = Date.now(); // Record the start time
|
||||||
|
|
||||||
|
// Promise to handle polling logic
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const attemptFetch = async () => {
|
||||||
|
if (Date.now() - startTime > maxDuration) {
|
||||||
|
return reject(new Error("Maximum polling time exceeded"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(apiCall);
|
||||||
|
const data = await response.json();
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
resolve(data[0]); // Resolve the promise when data is found
|
||||||
|
} else {
|
||||||
|
setTimeout(attemptFetch, retryDelay);
|
||||||
|
retryDelay = Math.min(retryDelay * 2, 360000); // Ensure delay does not exceed 6 minutes
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
reject(error); // Reject the promise on error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
attemptFetch(); // Initial call to start the polling
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listenForChatMessage({ nodeBaseUrl, senderAddress, senderPublicKey, timestamp }) {
|
||||||
|
try {
|
||||||
|
let validApi = "";
|
||||||
|
const checkIfNodeBaseUrlIsAcceptable = apiEndpoints.find(
|
||||||
|
(item) => item === nodeBaseUrl
|
||||||
|
);
|
||||||
|
if (checkIfNodeBaseUrlIsAcceptable) {
|
||||||
|
validApi = checkIfNodeBaseUrlIsAcceptable;
|
||||||
|
} else {
|
||||||
|
validApi = await findUsableApi();
|
||||||
|
}
|
||||||
|
const wallet = await getSaveWallet();
|
||||||
|
const address = wallet.address0;
|
||||||
|
const before = timestamp + 5000
|
||||||
|
const after = timestamp - 5000
|
||||||
|
const apiCall = `${validApi}/chat/messages?involving=${senderAddress}&involving=${address}&reverse=true&limit=1&before=${before}&after=${after}`;
|
||||||
|
const encodedMessageObj = await fetchMessages(apiCall)
|
||||||
|
|
||||||
|
const resKeyPair = await getKeyPair()
|
||||||
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
|
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
|
const keyPair = {
|
||||||
|
privateKey: uint8PrivateKey,
|
||||||
|
publicKey: uint8PublicKey
|
||||||
|
};
|
||||||
|
const decodedMessage = decryptChatMessage(encodedMessageObj.data, keyPair.privateKey, senderPublicKey, encodedMessageObj.reference)
|
||||||
|
return { secretCode: decodedMessage };
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||||
if (request) {
|
if (request) {
|
||||||
switch (request.action) {
|
switch (request.action) {
|
||||||
@ -261,15 +391,21 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "getWalletInfo":
|
case "getWalletInfo":
|
||||||
chrome.storage.local.get(["walletInfo"], (result) => {
|
|
||||||
if (chrome.runtime.lastError) {
|
getKeyPair().then(()=> {
|
||||||
sendResponse({ error: chrome.runtime.lastError.message });
|
chrome.storage.local.get(["walletInfo"], (result) => {
|
||||||
} else if (result.walletInfo) {
|
if (chrome.runtime.lastError) {
|
||||||
sendResponse({ walletInfo: result.walletInfo });
|
sendResponse({ error: chrome.runtime.lastError.message });
|
||||||
} else {
|
} else if (result.walletInfo) {
|
||||||
sendResponse({ error: "No wallet info found" });
|
sendResponse({ walletInfo: result.walletInfo });
|
||||||
}
|
} else {
|
||||||
});
|
sendResponse({ error: "No wallet info found" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch((error)=> {
|
||||||
|
sendResponse({ error: error.message });
|
||||||
|
})
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "validApi":
|
case "validApi":
|
||||||
findUsableApi()
|
findUsableApi()
|
||||||
@ -298,6 +434,22 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "decryptWallet": {
|
||||||
|
const { password, wallet } = request.payload;
|
||||||
|
|
||||||
|
decryptWallet({
|
||||||
|
password, wallet, walletVersion
|
||||||
|
})
|
||||||
|
.then((hasDecrypted) => {
|
||||||
|
sendResponse(hasDecrypted);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
sendResponse({ error: error?.message });
|
||||||
|
console.error(error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case "balance":
|
case "balance":
|
||||||
getBalanceInfo()
|
getBalanceInfo()
|
||||||
.then((balance) => {
|
.then((balance) => {
|
||||||
@ -321,6 +473,21 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "oauth": {
|
||||||
|
const { nodeBaseUrl, senderAddress, senderPublicKey, timestamp } = request.payload;
|
||||||
|
|
||||||
|
listenForChatMessage({ nodeBaseUrl, senderAddress, senderPublicKey, timestamp })
|
||||||
|
.then(({ secretCode }) => {
|
||||||
|
sendResponse(secretCode);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
sendResponse({ error: error.message });
|
||||||
|
console.error(error.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "authentication":
|
case "authentication":
|
||||||
{
|
{
|
||||||
getSaveWallet()
|
getSaveWallet()
|
||||||
@ -333,7 +500,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
chrome.windows.getAll(
|
chrome.windows.getAll(
|
||||||
{ populate: true, windowTypes: ["popup"] },
|
{ populate: true, windowTypes: ["popup"] },
|
||||||
(windows) => {
|
(windows) => {
|
||||||
|
|
||||||
// Attempt to find an existing popup window that has a tab with the correct URL
|
// Attempt to find an existing popup window that has a tab with the correct URL
|
||||||
const existingPopup = windows.find(
|
const existingPopup = windows.find(
|
||||||
(w) =>
|
(w) =>
|
||||||
@ -396,7 +562,9 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
let intervalId = null;
|
let intervalId = null;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const checkInterval = 3000; // Check every 3 seconds
|
const checkInterval = 3000; // Check every 3 seconds
|
||||||
const timeout = request.timeout ? 0.75 * (request.timeout * 1000) : 60000; // Stop after 15 seconds
|
const timeout = request.timeout
|
||||||
|
? 0.75 * (request.timeout * 1000)
|
||||||
|
: 60000; // Stop after 15 seconds
|
||||||
|
|
||||||
const checkFunction = () => {
|
const checkFunction = () => {
|
||||||
getSaveWallet()
|
getSaveWallet()
|
||||||
@ -439,7 +607,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
chrome.windows.getAll(
|
chrome.windows.getAll(
|
||||||
{ populate: true, windowTypes: ["popup"] },
|
{ populate: true, windowTypes: ["popup"] },
|
||||||
(windows) => {
|
(windows) => {
|
||||||
|
|
||||||
// Attempt to find an existing popup window that has a tab with the correct URL
|
// Attempt to find an existing popup window that has a tab with the correct URL
|
||||||
const existingPopup = windows.find(
|
const existingPopup = windows.find(
|
||||||
(w) =>
|
(w) =>
|
||||||
@ -515,7 +682,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
chrome.windows.getAll(
|
chrome.windows.getAll(
|
||||||
{ populate: true, windowTypes: ["popup"] },
|
{ populate: true, windowTypes: ["popup"] },
|
||||||
(windows) => {
|
(windows) => {
|
||||||
|
|
||||||
// Attempt to find an existing popup window that has a tab with the correct URL
|
// Attempt to find an existing popup window that has a tab with the correct URL
|
||||||
const existingPopup = windows.find(
|
const existingPopup = windows.find(
|
||||||
(w) =>
|
(w) =>
|
||||||
@ -557,7 +723,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
|
|
||||||
const interactionId = Date.now().toString(); // Simple example; consider a better unique ID
|
const interactionId = Date.now().toString(); // Simple example; consider a better unique ID
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
chrome.runtime.sendMessage({
|
chrome.runtime.sendMessage({
|
||||||
action: "SET_COUNTDOWN",
|
action: "SET_COUNTDOWN",
|
||||||
@ -602,13 +767,14 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
sendResponse(true);
|
sendResponse(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pendingResponses.delete(interactionId3);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "sendQortConfirmation":
|
case "sendQortConfirmation":
|
||||||
const { password, amount, receiver, isDecline } = request.payload;
|
const { password, amount, receiver, isDecline } = request.payload;
|
||||||
const interactionId2 = request.payload.interactionId;
|
const interactionId2 = request.payload.interactionId;
|
||||||
|
|
||||||
// Retrieve the stored sendResponse callback
|
// Retrieve the stored sendResponse callback
|
||||||
const originalSendResponse = pendingResponses.get(interactionId2);
|
const originalSendResponse = pendingResponses.get(interactionId2);
|
||||||
|
|
||||||
@ -616,13 +782,16 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
if (isDecline) {
|
if (isDecline) {
|
||||||
originalSendResponse({ error: "User has declined" });
|
originalSendResponse({ error: "User has declined" });
|
||||||
sendResponse(false);
|
sendResponse(false);
|
||||||
|
pendingResponses.delete(interactionId2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendCoin({ password, amount, receiver })
|
sendCoin({ password, amount, receiver }, true)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
sendResponse(true);
|
sendResponse(true);
|
||||||
// Use the sendResponse callback to respond to the original message
|
// Use the sendResponse callback to respond to the original message
|
||||||
originalSendResponse(res);
|
originalSendResponse(res);
|
||||||
|
// Remove the callback from the Map as it's no longer needed
|
||||||
|
pendingResponses.delete(interactionId2);
|
||||||
// chrome.runtime.sendMessage({
|
// chrome.runtime.sendMessage({
|
||||||
// action: "closePopup",
|
// action: "closePopup",
|
||||||
// });
|
// });
|
||||||
@ -633,38 +802,38 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
originalSendResponse({ error: error.message });
|
originalSendResponse({ error: error.message });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove the callback from the Map as it's no longer needed
|
|
||||||
pendingResponses.delete(interactionId2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "logout" : {
|
case "logout":
|
||||||
chrome.storage.local.remove('walletInfo', () => {
|
{
|
||||||
if (chrome.runtime.lastError) {
|
chrome.storage.local.remove(["keyPair", "walletInfo"], () => {
|
||||||
// Handle error
|
if (chrome.runtime.lastError) {
|
||||||
console.error(chrome.runtime.lastError.message);
|
// Handle error
|
||||||
} else {
|
console.error(chrome.runtime.lastError.message);
|
||||||
// Data removed successfully
|
} else {
|
||||||
sendResponse(true)
|
chrome.tabs.query({}, function(tabs) {
|
||||||
}
|
tabs.forEach(tab => {
|
||||||
});
|
chrome.tabs.sendMessage(tab.id, { type: "LOGOUT" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Data removed successfully
|
||||||
|
sendResponse(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
break;
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
chrome.action.onClicked.addListener((tab) => {
|
chrome.action.onClicked.addListener((tab) => {
|
||||||
const popupUrl = chrome.runtime.getURL("index.html");
|
const popupUrl = chrome.runtime.getURL("index.html");
|
||||||
chrome.windows.getAll(
|
chrome.windows.getAll(
|
||||||
{ populate: true, windowTypes: ["popup"] },
|
{ populate: true, windowTypes: ["popup"] },
|
||||||
(windows) => {
|
(windows) => {
|
||||||
|
|
||||||
// Attempt to find an existing popup window that has a tab with the correct URL
|
// Attempt to find an existing popup window that has a tab with the correct URL
|
||||||
const existingPopup = windows.find(
|
const existingPopup = windows.find(
|
||||||
(w) =>
|
(w) =>
|
||||||
|
266
src/deps/ed2curve.ts
Normal file
266
src/deps/ed2curve.ts
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ed2curve: convert Ed25519 signing key pair into Curve25519
|
||||||
|
* key pair suitable for Diffie-Hellman key exchange.
|
||||||
|
*
|
||||||
|
* Written by Dmitry Chestnykh in 2014. Public domain.
|
||||||
|
*/
|
||||||
|
/* jshint newcap: false */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Change to es6 import/export
|
||||||
|
*/
|
||||||
|
|
||||||
|
import nacl from './nacl-fast'
|
||||||
|
|
||||||
|
// (function(root, f) {
|
||||||
|
// 'use strict';
|
||||||
|
// if (typeof module !== 'undefined' && module.exports) module.exports = f(require('tweetnacl'));
|
||||||
|
// else root.ed2curve = f(root.nacl);
|
||||||
|
// }(this, function(nacl) {
|
||||||
|
// 'use strict';
|
||||||
|
// if (!nacl) throw new Error('tweetnacl not loaded');
|
||||||
|
|
||||||
|
// -- Operations copied from TweetNaCl.js. --
|
||||||
|
|
||||||
|
var gf = function(init) {
|
||||||
|
var i, r = new Float64Array(16);
|
||||||
|
if (init) for (i = 0; i < init.length; i++) r[i] = init[i];
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
var gf0 = gf(),
|
||||||
|
gf1 = gf([1]),
|
||||||
|
D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]),
|
||||||
|
I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]);
|
||||||
|
|
||||||
|
function car25519(o) {
|
||||||
|
var c;
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
o[i] += 65536;
|
||||||
|
c = Math.floor(o[i] / 65536);
|
||||||
|
o[(i+1)*(i<15?1:0)] += c - 1 + 37 * (c-1) * (i===15?1:0);
|
||||||
|
o[i] -= (c * 65536);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sel25519(p, q, b) {
|
||||||
|
var t, c = ~(b-1);
|
||||||
|
for (var i = 0; i < 16; i++) {
|
||||||
|
t = c & (p[i] ^ q[i]);
|
||||||
|
p[i] ^= t;
|
||||||
|
q[i] ^= t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpack25519(o, n) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8);
|
||||||
|
o[15] &= 0x7fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// addition
|
||||||
|
function A(o, a, b) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < 16; i++) o[i] = (a[i] + b[i])|0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// subtraction
|
||||||
|
function Z(o, a, b) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < 16; i++) o[i] = (a[i] - b[i])|0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiplication
|
||||||
|
function M(o, a, b) {
|
||||||
|
var i, j, t = new Float64Array(31);
|
||||||
|
for (i = 0; i < 31; i++) t[i] = 0;
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
for (j = 0; j < 16; j++) {
|
||||||
|
t[i+j] += a[i] * b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < 15; i++) {
|
||||||
|
t[i] += 38 * t[i+16];
|
||||||
|
}
|
||||||
|
for (i = 0; i < 16; i++) o[i] = t[i];
|
||||||
|
car25519(o);
|
||||||
|
car25519(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
// squaring
|
||||||
|
function S(o, a) {
|
||||||
|
M(o, a, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inversion
|
||||||
|
function inv25519(o, i) {
|
||||||
|
var c = gf();
|
||||||
|
var a;
|
||||||
|
for (a = 0; a < 16; a++) c[a] = i[a];
|
||||||
|
for (a = 253; a >= 0; a--) {
|
||||||
|
S(c, c);
|
||||||
|
if(a !== 2 && a !== 4) M(c, c, i);
|
||||||
|
}
|
||||||
|
for (a = 0; a < 16; a++) o[a] = c[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
function pack25519(o, n) {
|
||||||
|
var i, j, b;
|
||||||
|
var m = gf(), t = gf();
|
||||||
|
for (i = 0; i < 16; i++) t[i] = n[i];
|
||||||
|
car25519(t);
|
||||||
|
car25519(t);
|
||||||
|
car25519(t);
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
m[0] = t[0] - 0xffed;
|
||||||
|
for (i = 1; i < 15; i++) {
|
||||||
|
m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1);
|
||||||
|
m[i-1] &= 0xffff;
|
||||||
|
}
|
||||||
|
m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1);
|
||||||
|
b = (m[15]>>16) & 1;
|
||||||
|
m[14] &= 0xffff;
|
||||||
|
sel25519(t, m, 1-b);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
o[2*i] = t[i] & 0xff;
|
||||||
|
o[2*i+1] = t[i] >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function par25519(a) {
|
||||||
|
var d = new Uint8Array(32);
|
||||||
|
pack25519(d, a);
|
||||||
|
return d[0] & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function vn(x, xi, y, yi, n) {
|
||||||
|
var i, d = 0;
|
||||||
|
for (i = 0; i < n; i++) d |= x[xi + i] ^ y[yi + i];
|
||||||
|
return (1 & ((d - 1) >>> 8)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function crypto_verify_32(x, xi, y, yi) {
|
||||||
|
return vn(x, xi, y, yi, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
function neq25519(a, b) {
|
||||||
|
var c = new Uint8Array(32), d = new Uint8Array(32);
|
||||||
|
pack25519(c, a);
|
||||||
|
pack25519(d, b);
|
||||||
|
return crypto_verify_32(c, 0, d, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pow2523(o, i) {
|
||||||
|
var c = gf();
|
||||||
|
var a;
|
||||||
|
for (a = 0; a < 16; a++) c[a] = i[a];
|
||||||
|
for (a = 250; a >= 0; a--) {
|
||||||
|
S(c, c);
|
||||||
|
if (a !== 1) M(c, c, i);
|
||||||
|
}
|
||||||
|
for (a = 0; a < 16; a++) o[a] = c[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
function set25519(r, a) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < 16; i++) r[i] = a[i] | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpackneg(r, p) {
|
||||||
|
var t = gf(), chk = gf(), num = gf(),
|
||||||
|
den = gf(), den2 = gf(), den4 = gf(),
|
||||||
|
den6 = gf();
|
||||||
|
|
||||||
|
set25519(r[2], gf1);
|
||||||
|
unpack25519(r[1], p);
|
||||||
|
S(num, r[1]);
|
||||||
|
M(den, num, D);
|
||||||
|
Z(num, num, r[2]);
|
||||||
|
A(den, r[2], den);
|
||||||
|
|
||||||
|
S(den2, den);
|
||||||
|
S(den4, den2);
|
||||||
|
M(den6, den4, den2);
|
||||||
|
M(t, den6, num);
|
||||||
|
M(t, t, den);
|
||||||
|
|
||||||
|
pow2523(t, t);
|
||||||
|
M(t, t, num);
|
||||||
|
M(t, t, den);
|
||||||
|
M(t, t, den);
|
||||||
|
M(r[0], t, den);
|
||||||
|
|
||||||
|
S(chk, r[0]);
|
||||||
|
M(chk, chk, den);
|
||||||
|
if (neq25519(chk, num)) M(r[0], r[0], I);
|
||||||
|
|
||||||
|
S(chk, r[0]);
|
||||||
|
M(chk, chk, den);
|
||||||
|
if (neq25519(chk, num)) return -1;
|
||||||
|
|
||||||
|
if (par25519(r[0]) === (p[31] >> 7)) Z(r[0], gf0, r[0]);
|
||||||
|
|
||||||
|
M(r[3], r[0], r[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
|
||||||
|
// Converts Ed25519 public key to Curve25519 public key.
|
||||||
|
// montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p
|
||||||
|
function convertPublicKey(pk) {
|
||||||
|
var z = new Uint8Array(32),
|
||||||
|
q = [gf(), gf(), gf(), gf()],
|
||||||
|
a = gf(), b = gf();
|
||||||
|
|
||||||
|
if (unpackneg(q, pk)) return null; // reject invalid key
|
||||||
|
|
||||||
|
var y = q[1];
|
||||||
|
|
||||||
|
A(a, gf1, y);
|
||||||
|
Z(b, gf1, y);
|
||||||
|
inv25519(b, b);
|
||||||
|
M(a, a, b);
|
||||||
|
|
||||||
|
pack25519(z, a);
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts Ed25519 secret key to Curve25519 secret key.
|
||||||
|
function convertSecretKey(sk) {
|
||||||
|
var d = new Uint8Array(64), o = new Uint8Array(32), i;
|
||||||
|
nacl.lowlevel.crypto_hash(d, sk, 32);
|
||||||
|
d[0] &= 248;
|
||||||
|
d[31] &= 127;
|
||||||
|
d[31] |= 64;
|
||||||
|
for (i = 0; i < 32; i++) o[i] = d[i];
|
||||||
|
for (i = 0; i < 64; i++) d[i] = 0;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertKeyPair(edKeyPair) {
|
||||||
|
var publicKey = convertPublicKey(edKeyPair.publicKey);
|
||||||
|
if (!publicKey) return null;
|
||||||
|
return {
|
||||||
|
publicKey: publicKey,
|
||||||
|
secretKey: convertSecretKey(edKeyPair.secretKey)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// convertPublicKey: convertPublicKey,
|
||||||
|
// convertSecretKey: convertSecretKey,
|
||||||
|
// convertKeyPair: convertKeyPair,
|
||||||
|
// };
|
||||||
|
|
||||||
|
export default {
|
||||||
|
convertPublicKey: convertPublicKey,
|
||||||
|
convertSecretKey: convertSecretKey,
|
||||||
|
convertKeyPair: convertKeyPair,
|
||||||
|
}
|
||||||
|
|
||||||
|
// }));
|
29
src/utils/decryptChatMessage.ts
Normal file
29
src/utils/decryptChatMessage.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import Base58 from '../deps/Base58'
|
||||||
|
import ed2curve from '../deps/ed2curve'
|
||||||
|
import nacl from '../deps/nacl-fast'
|
||||||
|
import {Sha256} from 'asmcrypto.js'
|
||||||
|
|
||||||
|
|
||||||
|
export const decryptChatMessage = (encryptedMessage, privateKey, recipientPublicKey, lastReference) => {
|
||||||
|
const test = encryptedMessage
|
||||||
|
let _encryptedMessage = Base58.decode(encryptedMessage)
|
||||||
|
const _base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? Base58.encode(recipientPublicKey) : recipientPublicKey
|
||||||
|
const _recipientPublicKey = Base58.decode(_base58RecipientPublicKey)
|
||||||
|
|
||||||
|
const _lastReference = lastReference instanceof Uint8Array ? lastReference : Base58.decode(lastReference)
|
||||||
|
|
||||||
|
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
|
||||||
|
const convertedPublicKey = ed2curve.convertPublicKey(_recipientPublicKey)
|
||||||
|
const sharedSecret = new Uint8Array(32);
|
||||||
|
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
|
||||||
|
|
||||||
|
const _chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result
|
||||||
|
const _decryptedMessage = nacl.secretbox.open(_encryptedMessage, _lastReference.slice(0, 24), _chatEncryptionSeed)
|
||||||
|
|
||||||
|
let decryptedMessage = ''
|
||||||
|
|
||||||
|
_decryptedMessage === false ? decryptedMessage : decryptedMessage = new TextDecoder('utf-8').decode(_decryptedMessage)
|
||||||
|
return decryptedMessage
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { crypto, walletVersion } from '../../constants/decryptWallet';
|
|||||||
import { doInitWorkers, kdf } from '../../deps/kdf';
|
import { doInitWorkers, kdf } from '../../deps/kdf';
|
||||||
import PhraseWallet from './phrase-wallet';
|
import PhraseWallet from './phrase-wallet';
|
||||||
import * as WORDLISTS from './wordlists';
|
import * as WORDLISTS from './wordlists';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
export function generateRandomSentence(template = 'adverb verb noun adjective noun adverb verb noun adjective noun adjective verbed adjective noun', maxWordLength = 0, capitalize = true) {
|
export function generateRandomSentence(template = 'adverb verb noun adjective noun adverb verb noun adjective noun adjective verbed adjective noun', maxWordLength = 0, capitalize = true) {
|
||||||
const partsOfSpeechMap = {
|
const partsOfSpeechMap = {
|
||||||
@ -83,63 +84,19 @@ export const createAccount = async()=> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const saveFileToDisk= async(data, qortAddress) => {
|
export const saveFileToDisk = async (data, qortAddress) => {
|
||||||
try {
|
try {
|
||||||
const dataString = JSON.stringify(data)
|
const dataString = JSON.stringify(data);
|
||||||
const blob = new Blob([dataString], { type: 'text/plain;charset=utf-8' })
|
const blob = new Blob([dataString], { type: 'application/json' });
|
||||||
const fileName = "qortal_backup_" + qortAddress + ".json"
|
const fileName = "qortal_backup_" + qortAddress + ".json";
|
||||||
// Feature detection. The API needs to be supported
|
|
||||||
// and the app not run in an iframe.
|
saveAs(blob, fileName);
|
||||||
const supportsFileSystemAccess =
|
|
||||||
'showSaveFilePicker' in window &&
|
|
||||||
(() => {
|
|
||||||
try {
|
|
||||||
return window.self === window.top
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
// If the File System Access API is supported...
|
|
||||||
if (supportsFileSystemAccess) {
|
|
||||||
try {
|
|
||||||
// Show the file save dialog.
|
|
||||||
const fileHandle = await window.showSaveFilePicker({
|
|
||||||
suggestedName: fileName,
|
|
||||||
types: [{
|
|
||||||
description: "File",
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
// Write the blob to the file.
|
|
||||||
const writable = await fileHandle.createWritable()
|
|
||||||
await writable.write(blob)
|
|
||||||
await writable.close()
|
|
||||||
console.log("FILE SAVED")
|
|
||||||
return
|
|
||||||
} catch (err) {
|
|
||||||
// Fail silently if the user has simply canceled the dialog.
|
|
||||||
if (err.name === 'AbortError') {
|
|
||||||
console.error(err.name, err.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Fallback if the File System Access API is not supported...
|
|
||||||
// Create the blob URL.
|
|
||||||
const blobURL = URL.createObjectURL(blob)
|
|
||||||
// Create the `<a download>` element and append it invisibly.
|
|
||||||
const a = document.createElement('a')
|
|
||||||
a.href = blobURL
|
|
||||||
a.download = fileName
|
|
||||||
a.style.display = 'none'
|
|
||||||
document.body.append(a)
|
|
||||||
// Programmatically click the element.
|
|
||||||
a.click()
|
|
||||||
// Revoke the blob URL and remove the element.
|
|
||||||
setTimeout(() => {
|
|
||||||
URL.revokeObjectURL(blobURL);
|
|
||||||
a.remove();
|
|
||||||
}, 1000);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log({error})
|
console.log({ error });
|
||||||
|
if (error.name === 'AbortError') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// This fallback will only be executed if the `showSaveFilePicker` method fails.
|
||||||
|
FileSaver.saveAs(blob, fileName); // Ensure FileSaver is properly imported or available in your environment.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user