import React, { useCallback, useContext, useEffect, useRef, useState, } from 'react'; import { Spacer } from '../common/Spacer'; import { CustomButton, TextP, TextSpan } from '../styles/App-styles'; import { Box, Button, ButtonBase, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, Input, styled, Switch, TextField, Typography, useTheme, } from '@mui/material'; import Logo1Dark from '../assets/svgs/Logo1Dark.svg'; import HelpIcon from '@mui/icons-material/Help'; import { CustomizedSnackbars } from '../components/Snackbar/Snackbar'; import { cleanUrl, gateways } from '../background'; import { GlobalContext } from '../App'; import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip'; import ThemeSelector from '../components/Theme/ThemeSelector'; import { useTranslation } from 'react-i18next'; import LanguageSelector from '../components/Language/LanguageSelector'; const manifestData = { version: '0.5.3', }; export const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( ))(({ theme }) => ({ [`& .${tooltipClasses.tooltip}`]: { backgroundColor: theme.palette.background.paper, color: theme.palette.text.primary, maxWidth: 320, padding: '20px', fontSize: theme.typography.pxToRem(12), }, })); function removeTrailingSlash(url) { return url.replace(/\/+$/, ''); } export const NotAuthenticated = ({ getRootProps, getInputProps, setExtstate, apiKey, setApiKey, globalApiKey, handleSetGlobalApikey, currentNode, setCurrentNode, useLocalNode, setUseLocalNode, }) => { const [isValidApiKey, setIsValidApiKey] = useState(null); const [hasLocalNode, setHasLocalNode] = useState(null); // const [useLocalNode, setUseLocalNode] = useState(false); const [openSnack, setOpenSnack] = React.useState(false); const [infoSnack, setInfoSnack] = React.useState(null); const [show, setShow] = React.useState(false); const [mode, setMode] = React.useState('list'); const [customNodes, setCustomNodes] = React.useState(null); // const [currentNode, setCurrentNode] = React.useState({ // url: "http://127.0.0.1:12391", // }); const [importedApiKey, setImportedApiKey] = React.useState(null); //add and edit states const [url, setUrl] = React.useState('https://'); const [customApikey, setCustomApiKey] = React.useState(''); const [showSelectApiKey, setShowSelectApiKey] = useState(false); const [enteredApiKey, setEnteredApiKey] = useState(''); const [customNodeToSaveIndex, setCustomNodeToSaveIndex] = React.useState(null); const { showTutorial, hasSeenGettingStarted } = useContext(GlobalContext); const theme = useTheme(); const { t } = useTranslation(['auth', 'core']); const importedApiKeyRef = useRef(null); const currentNodeRef = useRef(null); const hasLocalNodeRef = useRef(null); const isLocal = cleanUrl(currentNode?.url) === '127.0.0.1:12391'; const handleFileChangeApiKey = (event) => { setShowSelectApiKey(false); const file = event.target.files[0]; // Get the selected file if (file) { const reader = new FileReader(); reader.onload = (e) => { const text = e.target.result; // Get the file content setImportedApiKey(text); // Store the file content in the state if (customNodes) { setCustomNodes((prev) => { const copyPrev = [...prev]; const findLocalIndex = copyPrev?.findIndex( (item) => item?.url === 'http://127.0.0.1:12391' ); if (findLocalIndex === -1) { copyPrev.unshift({ url: 'http://127.0.0.1:12391', apikey: text, }); } else { copyPrev[findLocalIndex] = { url: 'http://127.0.0.1:12391', apikey: text, }; } window.sendMessage('setCustomNodes', copyPrev).catch((error) => { console.error( 'Failed to set custom nodes:', error.message || 'An error occurred' ); }); return copyPrev; }); } }; reader.readAsText(file); // Read the file as text } }; const checkIfUserHasLocalNode = useCallback(async () => { try { const url = `http://127.0.0.1:12391/admin/status`; const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }); const data = await response.json(); if (data?.height) { setHasLocalNode(true); return true; } return false; } catch (error) { return false; } }, []); useEffect(() => { checkIfUserHasLocalNode(); }, []); useEffect(() => { window .sendMessage('getCustomNodesFromStorage') .then((response) => { setCustomNodes(response || []); if (window?.electronAPI?.setAllowedDomains) { window.electronAPI.setAllowedDomains( response?.map((node) => node.url) ); } if (Array.isArray(response)) { const findLocal = response?.find( (item) => item?.url === 'http://127.0.0.1:12391' ); if (findLocal && findLocal?.apikey) { setImportedApiKey(findLocal?.apikey); } } }) .catch((error) => { console.error( 'Failed to get custom nodes from storage:', error.message || 'An error occurred' ); }); }, []); useEffect(() => { importedApiKeyRef.current = importedApiKey; }, [importedApiKey]); useEffect(() => { currentNodeRef.current = currentNode; }, [currentNode]); useEffect(() => { hasLocalNodeRef.current = hasLocalNode; }, [hasLocalNode]); const validateApiKey = useCallback(async (key, fromStartUp) => { try { if (key === 'isGateway') return; const isLocalKey = cleanUrl(key?.url) === '127.0.0.1:12391'; if ( fromStartUp && key?.url && key?.apikey && !isLocalKey && !gateways.some((gateway) => key?.url?.includes(gateway)) ) { setCurrentNode({ url: key?.url, apikey: key?.apikey, }); let isValid = false; const url = `${key?.url}/admin/settings/localAuthBypassEnabled`; const response = await fetch(url); // Assuming the response is in plain text and will be 'true' or 'false' const data = await response.text(); if (data && data === 'true') { isValid = true; } else { const url2 = `${key?.url}/admin/apikey/test?apiKey=${key?.apikey}`; const response2 = await fetch(url2); // Assuming the response is in plain text and will be 'true' or 'false' const data2 = await response2.text(); if (data2 === 'true') { isValid = true; } } if (isValid) { setIsValidApiKey(true); setUseLocalNode(true); return; } } if (!currentNodeRef.current) return; const stillHasLocal = await checkIfUserHasLocalNode(); if (isLocalKey && !stillHasLocal && !fromStartUp) { throw new Error('Please turn on your local node'); } //check custom nodes // !gateways.some(gateway => apiKey?.url?.includes(gateway)) const isCurrentNodeLocal = cleanUrl(currentNodeRef.current?.url) === '127.0.0.1:12391'; if (isLocalKey && !isCurrentNodeLocal) { setIsValidApiKey(false); setUseLocalNode(false); return; } let payload = {}; if (currentNodeRef.current?.url === 'http://127.0.0.1:12391') { payload = { apikey: importedApiKeyRef.current || key?.apikey, url: currentNodeRef.current?.url, }; if (!payload?.apikey) { try { const generateUrl = 'http://127.0.0.1:12391/admin/apikey/generate'; const generateRes = await fetch(generateUrl, { method: 'POST', }); let res; try { res = await generateRes.clone().json(); } catch (e) { res = await generateRes.text(); } if (res != null && !res.error && res.length >= 8) { payload = { apikey: res, url: currentNodeRef.current?.url, }; setImportedApiKey(res); // Store the file content in the state setCustomNodes((prev) => { const copyPrev = [...prev]; const findLocalIndex = copyPrev?.findIndex( (item) => item?.url === 'http://127.0.0.1:12391' ); if (findLocalIndex === -1) { copyPrev.unshift({ url: 'http://127.0.0.1:12391', apikey: res, }); } else { copyPrev[findLocalIndex] = { url: 'http://127.0.0.1:12391', apikey: res, }; } window .sendMessage('setCustomNodes', copyPrev) .catch((error) => { console.error( 'Failed to set custom nodes:', error.message || 'An error occurred' ); }); return copyPrev; }); } } catch (error) { console.error(error); } } } else if (currentNodeRef.current) { payload = currentNodeRef.current; } let isValid = false; const url = `${payload?.url}/admin/settings/localAuthBypassEnabled`; const response = await fetch(url); // Assuming the response is in plain text and will be 'true' or 'false' const data = await response.text(); if (data && data === 'true') { isValid = true; } else { const url2 = `${payload?.url}/admin/apikey/test?apiKey=${payload?.apikey}`; const response2 = await fetch(url2); // Assuming the response is in plain text and will be 'true' or 'false' const data2 = await response2.text(); if (data2 === 'true') { isValid = true; } } if (isValid) { window .sendMessage('setApiKey', payload) .then((response) => { if (response) { handleSetGlobalApikey(payload); setIsValidApiKey(true); setUseLocalNode(true); if (!fromStartUp) { setApiKey(payload); } } }) .catch((error) => { console.error( 'Failed to set API key:', error.message || t('core:error', { postProcess: 'capitalize' }) ); }); } else { setIsValidApiKey(false); setUseLocalNode(false); if (!fromStartUp) { setInfoSnack({ type: 'error', message: t('auth:apikey.select_valid', { postProcess: 'capitalize', }), }); setOpenSnack(true); } } } catch (error) { setIsValidApiKey(false); setUseLocalNode(false); if (fromStartUp) { setCurrentNode({ url: 'http://127.0.0.1:12391', }); window .sendMessage('setApiKey', 'isGateway') .then((response) => { if (response) { setApiKey(null); handleSetGlobalApikey(null); } }) .catch((error) => { console.error( 'Failed to set API key:', error.message || t('core:error', { postProcess: 'capitalize', }) ); }); return; } if (!fromStartUp) { setInfoSnack({ type: 'error', message: error?.message || t('auth:apikey.select_valid', { postProcess: 'capitalize', }), }); setOpenSnack(true); } console.error('Error validating API key:', error); } }, []); useEffect(() => { if (apiKey) { validateApiKey(apiKey, true); } }, [apiKey]); const addCustomNode = () => { setMode('add-node'); }; const saveCustomNodes = (myNodes, isFullListOfNodes) => { let nodes = [...(myNodes || [])]; if (!isFullListOfNodes && customNodeToSaveIndex !== null) { nodes.splice(customNodeToSaveIndex, 1, { url: removeTrailingSlash(url), apikey: customApikey, }); } else if (!isFullListOfNodes && url) { nodes.push({ url: removeTrailingSlash(url), apikey: customApikey, }); } setCustomNodes(nodes); setCustomNodeToSaveIndex(null); if (!nodes) return; window .sendMessage('setCustomNodes', nodes) .then((response) => { if (response) { setMode('list'); setUrl('https://'); setCustomApiKey(''); if (window?.electronAPI?.setAllowedDomains) { window.electronAPI.setAllowedDomains( nodes?.map((node) => node.url) ); } // add alert if needed } }) .catch((error) => { console.error( 'Failed to set custom nodes:', error.message || 'An error occurred' ); }); }; return ( <>
{t('auth:welcome', { postProcess: 'capitalize' })} {' '} QORTAL {t('auth:tips.digital_id', { postProcess: 'capitalize' })} } > setExtstate('wallets')}> {t('auth:account.account_many', { postProcess: 'capitalize' })} {t('auth:tips.new_users', { postProcess: 'capitalize' })} {t('auth:tips.new_account', { postProcess: 'capitalize' })} } > { setExtstate('create-wallet'); }} sx={{ backgroundColor: hasSeenGettingStarted === false && 'var(--green)', color: hasSeenGettingStarted === false && 'black', '&:hover': { backgroundColor: hasSeenGettingStarted === false && 'var(--green)', color: hasSeenGettingStarted === false && 'black', }, }} > {t('auth:create_account', { postProcess: 'capitalize' })} {t('auth:node.using', { postProcess: 'capitalize' })}:{' '} {currentNode?.url} <> <> {t('auth:advanced_users', { postProcess: 'capitalize' })} { if (event.target.checked) { validateApiKey(currentNode); } else { setCurrentNode({ url: 'http://127.0.0.1:12391', }); setUseLocalNode(false); window .sendMessage('setApiKey', null) .then((response) => { if (response) { setApiKey(null); handleSetGlobalApikey(null); } }) .catch((error) => { console.error( 'Failed to set API key:', error.message || 'An error occurred' ); }); } }} disabled={false} /> } label={ isLocal ? t('auth:node.use_local', { postProcess: 'capitalize' }) : t('auth:node.use_custom', { postProcess: 'capitalize' }) } /> {currentNode?.url === 'http://127.0.0.1:12391' && ( <> {t('auth:apikey.key', { postProcess: 'capitalize' })}:{' '} {importedApiKey} )} {t('auth:build_version', { postProcess: 'capitalize' })}: {manifestData?.version} {show && ( {' '} {t('auth:node.custom_many', { postProcess: 'capitalize' })}: {mode === 'list' && ( http://127.0.0.1:12391 {customNodes?.map((node, index) => { return ( {node?.url} ); })} )} {mode === 'add-node' && ( { setUrl(e.target.value); }} /> { setCustomApiKey(e.target.value); }} /> )} {mode === 'list' && ( )} {mode === 'list' && ( <> )} {mode === 'add-node' && ( <> )} )} {showSelectApiKey && ( {t('auth:apikey.enter', { postProcess: 'capitalize' })} setEnteredApiKey(e.target.value)} /> )} { showTutorial('create-account', true); }} sx={{ position: 'fixed', bottom: '25px', right: '25px', }} > ); };