mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-04-25 04:17:53 +00:00
fixed file picker permisson, added node action
This commit is contained in:
parent
e5fabf198c
commit
3fbf16819a
@ -9,10 +9,12 @@ android {
|
|||||||
|
|
||||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(':capacitor-app')
|
||||||
implementation project(':capacitor-browser')
|
implementation project(':capacitor-browser')
|
||||||
implementation project(':capacitor-filesystem')
|
implementation project(':capacitor-filesystem')
|
||||||
implementation project(':capacitor-local-notifications')
|
implementation project(':capacitor-local-notifications')
|
||||||
implementation project(':capacitor-splash-screen')
|
implementation project(':capacitor-splash-screen')
|
||||||
|
implementation project(':capawesome-capacitor-file-picker')
|
||||||
implementation project(':evva-capacitor-secure-storage-plugin')
|
implementation project(':evva-capacitor-secure-storage-plugin')
|
||||||
implementation project(':transistorsoft-capacitor-background-fetch')
|
implementation project(':transistorsoft-capacitor-background-fetch')
|
||||||
implementation "androidx.webkit:webkit:1.4.0"
|
implementation "androidx.webkit:webkit:1.4.0"
|
||||||
|
@ -42,4 +42,7 @@
|
|||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||||
|
<!-- Needed if you want to retrieve unredacted EXIF metadata from photos -->
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
include ':capacitor-android'
|
include ':capacitor-android'
|
||||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||||
|
|
||||||
|
include ':capacitor-app'
|
||||||
|
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
|
||||||
|
|
||||||
include ':capacitor-browser'
|
include ':capacitor-browser'
|
||||||
project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
|
project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
|
||||||
|
|
||||||
@ -14,6 +17,9 @@ project(':capacitor-local-notifications').projectDir = new File('../node_modules
|
|||||||
include ':capacitor-splash-screen'
|
include ':capacitor-splash-screen'
|
||||||
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
|
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
|
||||||
|
|
||||||
|
include ':capawesome-capacitor-file-picker'
|
||||||
|
project(':capawesome-capacitor-file-picker').projectDir = new File('../node_modules/@capawesome/capacitor-file-picker/android')
|
||||||
|
|
||||||
include ':evva-capacitor-secure-storage-plugin'
|
include ':evva-capacitor-secure-storage-plugin'
|
||||||
project(':evva-capacitor-secure-storage-plugin').projectDir = new File('../node_modules/@evva/capacitor-secure-storage-plugin/android')
|
project(':evva-capacitor-secure-storage-plugin').projectDir = new File('../node_modules/@evva/capacitor-secure-storage-plugin/android')
|
||||||
|
|
||||||
|
1524
package-lock.json
generated
1524
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,14 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^6.1.2",
|
"@capacitor/android": "^6.1.2",
|
||||||
|
"@capacitor/app": "^6.0.1",
|
||||||
"@capacitor/browser": "^6.0.3",
|
"@capacitor/browser": "^6.0.3",
|
||||||
"@capacitor/cli": "^6.1.2",
|
"@capacitor/cli": "^6.1.2",
|
||||||
"@capacitor/core": "^6.1.2",
|
"@capacitor/core": "^6.1.2",
|
||||||
"@capacitor/filesystem": "^6.0.1",
|
"@capacitor/filesystem": "^6.0.1",
|
||||||
"@capacitor/local-notifications": "^6.1.0",
|
"@capacitor/local-notifications": "^6.1.0",
|
||||||
"@capacitor/splash-screen": "^6.0.2",
|
"@capacitor/splash-screen": "^6.0.2",
|
||||||
|
"@capawesome/capacitor-file-picker": "^6.1.0",
|
||||||
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
||||||
"@dnd-kit/core": "^6.1.0",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
@ -89,6 +91,7 @@
|
|||||||
"@types/react-virtualized": "^9.21.30",
|
"@types/react-virtualized": "^9.21.30",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
||||||
"@typescript-eslint/parser": "^7.1.1",
|
"@typescript-eslint/parser": "^7.1.1",
|
||||||
|
"@vitejs/plugin-legacy": "^5.4.3",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"esbuild-plugin-react-virtualized": "^1.0.4",
|
"esbuild-plugin-react-virtualized": "^1.0.4",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
|
47
src/App.tsx
47
src/App.tsx
@ -42,6 +42,7 @@ import Return from "./assets/svgs/Return.svg";
|
|||||||
import Success from "./assets/svgs/Success.svg";
|
import Success from "./assets/svgs/Success.svg";
|
||||||
import Info from "./assets/svgs/Info.svg";
|
import Info from "./assets/svgs/Info.svg";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { FilePicker } from '@capawesome/capacitor-file-picker';
|
||||||
import {
|
import {
|
||||||
createAccount,
|
createAccount,
|
||||||
generateRandomSentence,
|
generateRandomSentence,
|
||||||
@ -221,7 +222,6 @@ async function checkForUpdateFromGitHub() {
|
|||||||
|
|
||||||
if (isNewerVersion(currentVersion, latestVersion)) {
|
if (isNewerVersion(currentVersion, latestVersion)) {
|
||||||
const apkAsset = latestRelease.assets.find(asset => asset.name.endsWith('.apk'));
|
const apkAsset = latestRelease.assets.find(asset => asset.name.endsWith('.apk'));
|
||||||
console.log('apkAsset', apkAsset)
|
|
||||||
if (apkAsset) {
|
if (apkAsset) {
|
||||||
// Prompt user to download the APK if a new version is available
|
// Prompt user to download the APK if a new version is available
|
||||||
promptUserToUpdate(apkAsset.browser_download_url);
|
promptUserToUpdate(apkAsset.browser_download_url);
|
||||||
@ -608,6 +608,48 @@ function App() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleFilePick = async () => {
|
||||||
|
try {
|
||||||
|
const resultPermission = await FilePicker.checkPermissions();
|
||||||
|
// Open the file picker to select a JSON file
|
||||||
|
const result = await FilePicker.pickFiles({
|
||||||
|
types: ['application/json'], // Restrict to JSON files
|
||||||
|
multiple: false, // Allow only one file
|
||||||
|
readData: true,
|
||||||
|
|
||||||
|
});
|
||||||
|
if (result.files.length > 0) {
|
||||||
|
const decodedData = atob(result.files[0].data); // `atob` decodes Base64 to a string
|
||||||
|
const parsedFile = JSON.parse(decodedData);
|
||||||
|
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
const requiredFields = [
|
||||||
|
"address0",
|
||||||
|
"salt",
|
||||||
|
"iv",
|
||||||
|
"version",
|
||||||
|
"encryptedSeed",
|
||||||
|
"mac",
|
||||||
|
"kdfThreads",
|
||||||
|
];
|
||||||
|
for (const field of requiredFields) {
|
||||||
|
if (!(field in parsedFile)) throw new Error(`${field} not found in JSON`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the state with parsed wallet data
|
||||||
|
setRawWallet(parsedFile);
|
||||||
|
setExtstate("wallet-dropped");
|
||||||
|
setdecryptedWallet(null);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("No file selected.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error picking JSON file:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const saveWalletFunc = async (password: string) => {
|
const saveWalletFunc = async (password: string) => {
|
||||||
let wallet = structuredClone(rawWallet);
|
let wallet = structuredClone(rawWallet);
|
||||||
|
|
||||||
@ -705,7 +747,7 @@ function App() {
|
|||||||
if (message.action === "QORTAL_REQUEST_PERMISSION") {
|
if (message.action === "QORTAL_REQUEST_PERMISSION") {
|
||||||
try {
|
try {
|
||||||
if(message?.payload?.checkbox1){
|
if(message?.payload?.checkbox1){
|
||||||
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1
|
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1?.value || false
|
||||||
}
|
}
|
||||||
await showQortalRequestExtension(message?.payload);
|
await showQortalRequestExtension(message?.payload);
|
||||||
if (qortalRequestCheckbox1Ref.current) {
|
if (qortalRequestCheckbox1Ref.current) {
|
||||||
@ -1576,6 +1618,7 @@ function App() {
|
|||||||
<NotAuthenticated
|
<NotAuthenticated
|
||||||
getRootProps={getRootProps}
|
getRootProps={getRootProps}
|
||||||
getInputProps={getInputProps}
|
getInputProps={getInputProps}
|
||||||
|
handleFilePick={handleFilePick}
|
||||||
setExtstate={setExtstate}
|
setExtstate={setExtstate}
|
||||||
apiKey={apiKey}
|
apiKey={apiKey}
|
||||||
globalApiKey={globalApiKey}
|
globalApiKey={globalApiKey}
|
||||||
|
@ -36,6 +36,7 @@ export const NotAuthenticated = ({
|
|||||||
setApiKey,
|
setApiKey,
|
||||||
globalApiKey,
|
globalApiKey,
|
||||||
handleSetGlobalApikey,
|
handleSetGlobalApikey,
|
||||||
|
handleFilePick
|
||||||
}) => {
|
}) => {
|
||||||
const [isValidApiKey, setIsValidApiKey] = useState<boolean | null>(null);
|
const [isValidApiKey, setIsValidApiKey] = useState<boolean | null>(null);
|
||||||
const [hasLocalNode, setHasLocalNode] = useState<boolean | null>(null);
|
const [hasLocalNode, setHasLocalNode] = useState<boolean | null>(null);
|
||||||
@ -263,8 +264,7 @@ export const NotAuthenticated = ({
|
|||||||
marginLeft: "28px",
|
marginLeft: "28px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CustomButton {...getRootProps()}>
|
<CustomButton onClick={handleFilePick}>
|
||||||
<input {...getInputProps()} />
|
|
||||||
Authenticate
|
Authenticate
|
||||||
</CustomButton>
|
</CustomButton>
|
||||||
<Tooltip title="Authenticate by importing your Qortal JSON file" arrow>
|
<Tooltip title="Authenticate by importing your Qortal JSON file" arrow>
|
||||||
|
@ -28,6 +28,14 @@ export const sortablePinnedAppsAtom = atom({
|
|||||||
{
|
{
|
||||||
name: 'Q-Trade',
|
name: 'Q-Trade',
|
||||||
service: 'APP'
|
service: 'APP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Q-Support',
|
||||||
|
service: 'APP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'NodeInfo',
|
||||||
|
service: 'APP'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
} from "./backgroundFunctions/encryption";
|
} from "./backgroundFunctions/encryption";
|
||||||
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from "./constants/codes";
|
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from "./constants/codes";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
|
import { App as CapacitorApp } from '@capacitor/app';
|
||||||
import Base58 from "./deps/Base58";
|
import Base58 from "./deps/Base58";
|
||||||
import {
|
import {
|
||||||
base64ToUint8Array,
|
base64ToUint8Array,
|
||||||
@ -19,6 +19,7 @@ import {
|
|||||||
encryptSingle,
|
encryptSingle,
|
||||||
objectToBase64,
|
objectToBase64,
|
||||||
} from "./qdn/encryption/group-encryption";
|
} from "./qdn/encryption/group-encryption";
|
||||||
|
import { FilePicker } from '@capawesome/capacitor-file-picker';
|
||||||
import { reusableGet } from "./qdn/publish/pubish";
|
import { reusableGet } from "./qdn/publish/pubish";
|
||||||
import { signChat } from "./transactions/signChat";
|
import { signChat } from "./transactions/signChat";
|
||||||
import { createTransaction } from "./transactions/transactions";
|
import { createTransaction } from "./transactions/transactions";
|
||||||
@ -101,7 +102,14 @@ LocalNotifications.requestPermissions().then(permission => {
|
|||||||
if (permission.display === 'granted') {
|
if (permission.display === 'granted') {
|
||||||
console.log("Notifications enabled");
|
console.log("Notifications enabled");
|
||||||
}
|
}
|
||||||
});
|
}).catch((error)=> console.error(error));
|
||||||
|
|
||||||
|
FilePicker.requestPermissions().then(permission => {
|
||||||
|
if (permission?.publicStorage === 'granted') {
|
||||||
|
console.log("File access permission granted");
|
||||||
|
}
|
||||||
|
}).catch((error)=> console.error(error));;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function cleanUrl(url) {
|
export function cleanUrl(url) {
|
||||||
@ -3161,3 +3169,17 @@ LocalNotifications.addListener('localNotificationActionPerformed', async (event)
|
|||||||
console.error("Error clearing notifications:", error);
|
console.error("Error clearing notifications:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const initializeBackButton = () => {
|
||||||
|
|
||||||
|
CapacitorApp.addListener('backButton', (event) => {
|
||||||
|
// Prevent the app from closing on back button press
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call this function on app startup
|
||||||
|
initializeBackButton();
|
@ -15,7 +15,7 @@ export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
|
|||||||
const { rootHeight } = useContext(MyContext);
|
const { rootHeight } = useContext(MyContext);
|
||||||
// const iframeRef = useRef(null);
|
// const iframeRef = useRef(null);
|
||||||
const { document, window: frameWindow } = useFrame();
|
const { document, window: frameWindow } = useFrame();
|
||||||
const {path, history, changeCurrentIndex} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId)
|
const {path, history, changeCurrentIndex} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId, app?.name, app?.service)
|
||||||
const [url, setUrl] = useState('')
|
const [url, setUrl] = useState('')
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(()=> {
|
||||||
@ -162,7 +162,7 @@ export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
|
|||||||
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
width: '100%'
|
width: '100%'
|
||||||
}} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen">
|
}} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-modals" allow="fullscreen">
|
||||||
|
|
||||||
</iframe>
|
</iframe>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -39,7 +39,9 @@ const officialAppList = [
|
|||||||
"qombo",
|
"qombo",
|
||||||
"q-fund",
|
"q-fund",
|
||||||
"q-shop",
|
"q-shop",
|
||||||
"q-trade"
|
"q-trade",
|
||||||
|
"q-support",
|
||||||
|
"NodeInfo"
|
||||||
];
|
];
|
||||||
|
|
||||||
const ScrollerStyled = styled('div')({
|
const ScrollerStyled = styled('div')({
|
||||||
|
@ -42,7 +42,9 @@ const officialAppList = [
|
|||||||
"qombo",
|
"qombo",
|
||||||
"q-fund",
|
"q-fund",
|
||||||
"q-shop",
|
"q-shop",
|
||||||
"q-trade"
|
"q-trade",
|
||||||
|
"q-support",
|
||||||
|
"NodeInfo"
|
||||||
];
|
];
|
||||||
|
|
||||||
const ScrollerStyled = styled('div')({
|
const ScrollerStyled = styled('div')({
|
||||||
|
@ -184,7 +184,7 @@ const UIQortalRequests = [
|
|||||||
'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
|
'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
|
||||||
'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER',
|
'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER',
|
||||||
'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER',
|
'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER',
|
||||||
'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY'
|
'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY', 'ADMIN_ACTION'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@ -381,7 +381,7 @@ const UIQortalRequests = [
|
|||||||
return obj; // Updated object with references to stored files
|
return obj; // Updated object with references to stored files
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useQortalMessageListener = (frameWindow, iframeRef, tabId) => {
|
export const useQortalMessageListener = (frameWindow, iframeRef, tabId, appName, appService) => {
|
||||||
const [path, setPath] = useState('')
|
const [path, setPath] = useState('')
|
||||||
const [history, setHistory] = useState({
|
const [history, setHistory] = useState({
|
||||||
customQDNHistoryPaths: [],
|
customQDNHistoryPaths: [],
|
||||||
@ -435,7 +435,9 @@ isDOMContentLoaded: false
|
|||||||
if (event?.data?.requestedHandler !== 'UI') return;
|
if (event?.data?.requestedHandler !== 'UI') return;
|
||||||
|
|
||||||
const sendMessageToRuntime = (message, eventPort) => {
|
const sendMessageToRuntime = (message, eventPort) => {
|
||||||
window.sendMessage(message.action, message.payload, 300000, message.isExtension)
|
window.sendMessage(message.action, message.payload, 300000, message.isExtension, {
|
||||||
|
name: appName, service: appService
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
eventPort.postMessage({
|
eventPort.postMessage({
|
||||||
@ -552,7 +554,7 @@ isDOMContentLoaded: false
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}, []); // Empty dependency array to run once when the component mounts
|
}, [appName, appService]); // Empty dependency array to run once when the component mounts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,14 +24,14 @@ window.addEventListener("message", (event) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const sendMessageBackground = (action, data = {}, timeout = 60000, isExtension) => {
|
export const sendMessageBackground = (action, data = {}, timeout = 60000, isExtension, appInfo) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const requestId = generateRequestId(); // Unique ID for each request
|
const requestId = generateRequestId(); // Unique ID for each request
|
||||||
callbackMap.set(requestId, { resolve, reject }); // Store both resolve and reject callbacks
|
callbackMap.set(requestId, { resolve, reject }); // Store both resolve and reject callbacks
|
||||||
const targetOrigin = window.location.origin
|
const targetOrigin = window.location.origin
|
||||||
|
|
||||||
// Send the message with `backgroundMessage` type
|
// Send the message with `backgroundMessage` type
|
||||||
window.postMessage({ type: "backgroundMessage", action, requestId, payload: data, isExtension }, targetOrigin);
|
window.postMessage({ type: "backgroundMessage", action, requestId, payload: data, isExtension, appInfo }, targetOrigin);
|
||||||
|
|
||||||
// Set up a timeout to automatically reject if no response is received
|
// Set up a timeout to automatically reject if no response is received
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { gateways, getApiKeyFromStorage } from "./background";
|
import { gateways, getApiKeyFromStorage } from "./background";
|
||||||
import { addForeignServer, addListItems, cancelSellOrder, createBuyOrder, createPoll, decryptData, deleteListItems, deployAt, encryptData, getCrossChainServerInfo, getDaySummary, getForeignFee, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get";
|
import { addForeignServer, addListItems, adminAction, cancelSellOrder, createBuyOrder, createPoll, decryptData, deleteListItems, deployAt, encryptData, getCrossChainServerInfo, getDaySummary, getForeignFee, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get";
|
||||||
import { getData, storeData } from "./utils/chromeStorage";
|
import { getData, storeData } from "./utils/chromeStorage";
|
||||||
|
|
||||||
|
|
||||||
@ -69,6 +69,7 @@ export const isRunningGateway = async ()=> {
|
|||||||
|
|
||||||
// Ensure the message is from a trusted source
|
// Ensure the message is from a trusted source
|
||||||
const isFromExtension = request?.isExtension;
|
const isFromExtension = request?.isExtension;
|
||||||
|
const appInfo = request?.appInfo;
|
||||||
if (request?.type !== "backgroundMessage") return; // Only process messages of type 'backgroundMessage'
|
if (request?.type !== "backgroundMessage") return; // Only process messages of type 'backgroundMessage'
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ export const isRunningGateway = async ()=> {
|
|||||||
switch (request.action) {
|
switch (request.action) {
|
||||||
case "GET_USER_ACCOUNT": {
|
case "GET_USER_ACCOUNT": {
|
||||||
try {
|
try {
|
||||||
const res = await getUserAccount();
|
const res = await getUserAccount({isFromExtension, appInfo});
|
||||||
event.source.postMessage({
|
event.source.postMessage({
|
||||||
requestId: request.requestId,
|
requestId: request.requestId,
|
||||||
action: request.action,
|
action: request.action,
|
||||||
@ -358,7 +359,7 @@ export const isRunningGateway = async ()=> {
|
|||||||
|
|
||||||
case "GET_WALLET_BALANCE": {
|
case "GET_WALLET_BALANCE": {
|
||||||
try {
|
try {
|
||||||
const res = await getWalletBalance(request.payload, false, isFromExtension);
|
const res = await getWalletBalance(request.payload, false, isFromExtension, appInfo);
|
||||||
event.source.postMessage({
|
event.source.postMessage({
|
||||||
requestId: request.requestId,
|
requestId: request.requestId,
|
||||||
action: request.action,
|
action: request.action,
|
||||||
@ -654,6 +655,25 @@ export const isRunningGateway = async ()=> {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "ADMIN_ACTION": {
|
||||||
|
try {
|
||||||
|
const res = await adminAction(request.payload, isFromExtension)
|
||||||
|
event.source.postMessage({
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: request.action,
|
||||||
|
payload: res,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
}, event.origin);
|
||||||
|
} catch (error) {
|
||||||
|
event.source.postMessage({
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: request.action,
|
||||||
|
error: error?.message,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
}, event.origin);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -282,8 +282,30 @@ async function getUserPermission(payload, isFromExtension) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const getUserAccount = async () => {
|
export const getUserAccount = async ({isFromExtension, appInfo}) => {
|
||||||
try {
|
try {
|
||||||
|
const value = (await getPermission(`qAPPAutoAuth-${appInfo?.name}`)) || false;
|
||||||
|
let skip = false;
|
||||||
|
if (value) {
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
let resPermission
|
||||||
|
if(!skip){
|
||||||
|
resPermission = await getUserPermission({
|
||||||
|
text1: "Do you give this application permission to authenticate?",
|
||||||
|
checkbox1: {
|
||||||
|
value: false,
|
||||||
|
label: "Always authenticate automatically",
|
||||||
|
},
|
||||||
|
}, isFromExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { accepted = false, checkbox1 = false } = resPermission || {};
|
||||||
|
if(resPermission){
|
||||||
|
setPermission(`qAPPAutoAuth-${appInfo?.name}`, checkbox1);
|
||||||
|
}
|
||||||
|
if (accepted || skip) {
|
||||||
|
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
const address = wallet.address0;
|
const address = wallet.address0;
|
||||||
const publicKey = wallet.publicKey;
|
const publicKey = wallet.publicKey;
|
||||||
@ -291,6 +313,10 @@ export const getUserAccount = async () => {
|
|||||||
address,
|
address,
|
||||||
publicKey,
|
publicKey,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error("User declined request");
|
||||||
|
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error("Unable to fetch user account");
|
throw new Error("Unable to fetch user account");
|
||||||
}
|
}
|
||||||
@ -365,8 +391,10 @@ export const decryptData = async (data) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getListItems = async (data, isFromExtension) => {
|
export const getListItems = async (data, isFromExtension) => {
|
||||||
const localNodeAvailable = await isUsingLocal()
|
const isGateway = await isRunningGateway()
|
||||||
if(!localNodeAvailable) throw new Error('Please use your local node.')
|
if(isGateway){
|
||||||
|
throw new Error('This action cannot be done through a gateway')
|
||||||
|
}
|
||||||
const requiredFields = ["list_name"];
|
const requiredFields = ["list_name"];
|
||||||
const missingFields: string[] = [];
|
const missingFields: string[] = [];
|
||||||
requiredFields.forEach((field) => {
|
requiredFields.forEach((field) => {
|
||||||
@ -417,8 +445,10 @@ export const getListItems = async (data, isFromExtension) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const addListItems = async (data, isFromExtension) => {
|
export const addListItems = async (data, isFromExtension) => {
|
||||||
const localNodeAvailable = await isUsingLocal()
|
const isGateway = await isRunningGateway()
|
||||||
if(!localNodeAvailable) throw new Error('Please use your local node.')
|
if(isGateway){
|
||||||
|
throw new Error('This action cannot be done through a gateway')
|
||||||
|
}
|
||||||
const requiredFields = ["list_name", "items"];
|
const requiredFields = ["list_name", "items"];
|
||||||
const missingFields: string[] = [];
|
const missingFields: string[] = [];
|
||||||
requiredFields.forEach((field) => {
|
requiredFields.forEach((field) => {
|
||||||
@ -470,8 +500,10 @@ export const addListItems = async (data, isFromExtension) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const deleteListItems = async (data, isFromExtension) => {
|
export const deleteListItems = async (data, isFromExtension) => {
|
||||||
const localNodeAvailable = await isUsingLocal()
|
const isGateway = await isRunningGateway()
|
||||||
if(!localNodeAvailable) throw new Error('Please use your local node.')
|
if(isGateway){
|
||||||
|
throw new Error('This action cannot be done through a gateway')
|
||||||
|
}
|
||||||
const requiredFields = ["list_name", "item"];
|
const requiredFields = ["list_name", "item"];
|
||||||
const missingFields: string[] = [];
|
const missingFields: string[] = [];
|
||||||
requiredFields.forEach((field) => {
|
requiredFields.forEach((field) => {
|
||||||
@ -1355,7 +1387,7 @@ export const getUserWallet = async (data, isFromExtension) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWalletBalance = async (data, bypassPermission?: boolean, isFromExtension) => {
|
export const getWalletBalance = async (data, bypassPermission?: boolean, isFromExtension, appInfo) => {
|
||||||
const requiredFields = ["coin"];
|
const requiredFields = ["coin"];
|
||||||
const missingFields: string[] = [];
|
const missingFields: string[] = [];
|
||||||
requiredFields.forEach((field) => {
|
requiredFields.forEach((field) => {
|
||||||
@ -1369,8 +1401,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
|
|||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = (await getPermission(`qAPPAutoWalletBalance-${data.coin}`)) || false;
|
const value = (await getPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`)) || false;
|
||||||
console.log('value', value)
|
|
||||||
let skip = false;
|
let skip = false;
|
||||||
if (value) {
|
if (value) {
|
||||||
skip = true;
|
skip = true;
|
||||||
@ -1389,7 +1420,8 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
|
|||||||
}
|
}
|
||||||
const { accepted = false, checkbox1 = false } = resPermission || {};
|
const { accepted = false, checkbox1 = false } = resPermission || {};
|
||||||
if(resPermission){
|
if(resPermission){
|
||||||
setPermission(`qAPPAutoWalletBalance-${data.coin}`, checkbox1);
|
setPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`, checkbox1);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (accepted || bypassPermission || skip) {
|
if (accepted || bypassPermission || skip) {
|
||||||
let coin = data.coin;
|
let coin = data.coin;
|
||||||
@ -2017,8 +2049,9 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const address = wallet.address0;
|
const address = wallet.address0;
|
||||||
const resKeyPair = await getKeyPair();
|
const resKeyPair = await getKeyPair();
|
||||||
const parsedData = resKeyPair;
|
const parsedData = resKeyPair;
|
||||||
const localNodeAvailable = await isUsingLocal()
|
const isGateway = await isRunningGateway()
|
||||||
if(checkCoin !== 'QORT' && !localNodeAvailable) throw new Error('Cannot send a non-QORT coin through the gateway. Please use your local node.')
|
|
||||||
|
if(checkCoin !== 'QORT' && isGateway) throw new Error('Cannot send a non-QORT coin through the gateway. Please use your local node.')
|
||||||
if (checkCoin === "QORT") {
|
if (checkCoin === "QORT") {
|
||||||
// Params: data.coin, data.destinationAddress, data.amount, data.fee
|
// Params: data.coin, data.destinationAddress, data.amount, data.fee
|
||||||
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
|
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
|
||||||
@ -2715,4 +2748,60 @@ export const cancelSellOrder = async (data, isFromExtension) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error?.message || "Failed to submit sell order.");
|
throw new Error(error?.message || "Failed to submit sell order.");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const adminAction = async (data, isFromExtension) => {
|
||||||
|
const requiredFields = [
|
||||||
|
"type",
|
||||||
|
];
|
||||||
|
const missingFields: string[] = [];
|
||||||
|
requiredFields.forEach((field) => {
|
||||||
|
if (!data[field]) {
|
||||||
|
missingFields.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (missingFields.length > 0) {
|
||||||
|
const missingFieldsString = missingFields.join(", ");
|
||||||
|
const errorMsg = `Missing fields: ${missingFieldsString}`;
|
||||||
|
throw new Error(errorMsg);
|
||||||
|
}
|
||||||
|
const isGateway = await isRunningGateway()
|
||||||
|
if(isGateway){
|
||||||
|
throw new Error('This action cannot be done through a gateway')
|
||||||
|
}
|
||||||
|
|
||||||
|
let apiEndpoint = '';
|
||||||
|
switch (data.type.toLowerCase()) {
|
||||||
|
case 'stop':
|
||||||
|
apiEndpoint = await createEndpoint('/admin/stop');
|
||||||
|
break;
|
||||||
|
case 'restart':
|
||||||
|
apiEndpoint = await createEndpoint('/admin/restart');
|
||||||
|
break;
|
||||||
|
case 'bootstrap':
|
||||||
|
apiEndpoint = await createEndpoint('/admin/bootstrap');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown admin action type: ${data.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resPermission = await getUserPermission({
|
||||||
|
text1: `Do you give this application permission to perform a node ${data.type}?`,
|
||||||
|
}, isFromExtension);
|
||||||
|
const { accepted } = resPermission;
|
||||||
|
if (accepted) {
|
||||||
|
const response = await fetch(apiEndpoint);
|
||||||
|
if (!response.ok) throw new Error("Failed to perform request");
|
||||||
|
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await response.clone().json();
|
||||||
|
} catch (e) {
|
||||||
|
res = await response.text();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
throw new Error("User declined request");
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user