added admin action qortalrequest

This commit is contained in:
PhilReact 2024-11-13 05:05:40 +02:00
parent a625a2ce67
commit 95df97ba19
8 changed files with 139 additions and 23 deletions

View File

@ -629,7 +629,7 @@ function App() {
if (message.action === "QORTAL_REQUEST_PERMISSION" && isMainWindow) {
try {
if(message?.payload?.checkbox1){
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1?.value || false
}
await showQortalRequestExtension(message?.payload);

View File

@ -28,6 +28,14 @@ export const sortablePinnedAppsAtom = atom({
{
name: 'Q-Trade',
service: 'APP'
},
{
name: 'Q-Support',
service: 'APP'
},
{
name: 'NodeInfo',
service: 'APP'
}
],
});

View File

@ -15,7 +15,7 @@ export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
const { rootHeight } = useContext(MyContext);
// const iframeRef = useRef(null);
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('')
useEffect(()=> {

View File

@ -42,7 +42,9 @@ const officialAppList = [
"qombo",
"q-fund",
"q-shop",
"q-trade"
"q-trade",
"q-support",
"NodeInfo"
];
const ScrollerStyled = styled('div')({

View File

@ -57,7 +57,9 @@ const officialAppList = [
"qombo",
"q-fund",
"q-shop",
"q-trade"
"q-trade",
"q-support",
"NodeInfo"
];
const ScrollerStyled = styled("div")({

View File

@ -140,7 +140,7 @@ const UIQortalRequests = [
'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER',
'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'
];
@ -317,7 +317,7 @@ const UIQortalRequests = [
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 [history, setHistory] = useState({
customQDNHistoryPaths: [],
@ -387,7 +387,9 @@ isDOMContentLoaded: false
// Check if action is included in the predefined list of UI requests
if (UIQortalRequests.includes(event.data.action)) {
sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: event.data, isExtension: true },
{ action: event.data.action, type: 'qortalRequest', payload: event.data, isExtension: true, appInfo: {
name: appName, service: appService
} },
event.ports[0]
);
} else if (
@ -465,7 +467,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
chrome.runtime?.onMessage.addListener( function (message, sender, sendResponse) {
if(message.action === "SHOW_SAVE_FILE_PICKER"){

View File

@ -1,5 +1,5 @@
import { getApiKeyFromStorage } from "./background";
import { addForeignServer, addListItems, cancelSellOrder, createBuyOrder, createPoll, createSellOrder, 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, createSellOrder, 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";
@ -74,9 +74,10 @@ function getLocalStorage(key) {
chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
if (request) {
const isFromExtension = request?.isExtension
const appInfo = request?.appInfo;
switch (request.action) {
case "GET_USER_ACCOUNT": {
getUserAccount()
getUserAccount({isFromExtension, appInfo})
.then((res) => {
sendResponse(res);
})
@ -270,7 +271,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "GET_WALLET_BALANCE": {
const data = request.payload;
getWalletBalance(data, false, isFromExtension)
getWalletBalance(data, false, isFromExtension, appInfo)
.then((res) => {
sendResponse(res);
})
@ -477,6 +478,17 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
});
break;
}
case "ADMIN_ACTION": {
adminAction(data, isFromExtension).then((res) => {
sendResponse(res);
})
.catch((error) => {
sendResponse({ error: error?.message });
});
break;
}
}
}
return true;

View File

@ -364,8 +364,30 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
});
}
export const getUserAccount = async () => {
export const getUserAccount = async ({isFromExtension, appInfo}) => {
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 address = wallet.address0;
const publicKey = wallet.publicKey;
@ -373,7 +395,12 @@ export const getUserAccount = async () => {
address,
publicKey,
};
} else {
throw new Error("User declined request");
}
} catch (error) {
console.log('per error', error)
throw new Error("Unable to fetch user account");
}
};
@ -447,8 +474,10 @@ export const decryptData = async (data) => {
};
export const getListItems = async (data, isFromExtension) => {
const localNodeAvailable = await isUsingLocal()
if(!localNodeAvailable) throw new Error('Please use your local node.')
const isGateway = await isRunningGateway()
if(isGateway){
throw new Error('This action cannot be done through a gateway')
}
const requiredFields = ["list_name"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -499,8 +528,10 @@ export const getListItems = async (data, isFromExtension) => {
};
export const addListItems = async (data, isFromExtension) => {
const localNodeAvailable = await isUsingLocal()
if(!localNodeAvailable) throw new Error('Please use your local node.')
const isGateway = await isRunningGateway()
if(isGateway){
throw new Error('This action cannot be done through a gateway')
}
const requiredFields = ["list_name", "items"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -552,8 +583,10 @@ export const addListItems = async (data, isFromExtension) => {
};
export const deleteListItems = async (data, isFromExtension) => {
const localNodeAvailable = await isUsingLocal()
if(!localNodeAvailable) throw new Error('Please use your local node.')
const isGateway = await isRunningGateway()
if(isGateway){
throw new Error('This action cannot be done through a gateway')
}
const requiredFields = ["list_name", "item"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1431,7 +1464,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 missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1445,7 +1478,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
throw new Error(errorMsg);
}
const value = (await getPermission(`qAPPAutoWalletBalance-${data.coin}`)) || false;
const value = (await getPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`)) || false;
let skip = false;
if (value) {
skip = true;
@ -1465,7 +1498,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
const { accepted = false, checkbox1 = false } = resPermission || {};
if(resPermission){
setPermission(`qAPPAutoWalletBalance-${data.coin}`, checkbox1);
setPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`, checkbox1);
}
if (accepted || bypassPermission || skip) {
let coin = data.coin;
@ -2093,8 +2126,9 @@ export const sendCoin = async (data, isFromExtension) => {
const address = wallet.address0;
const resKeyPair = await getKeyPair();
const parsedData = JSON.parse(resKeyPair);
const localNodeAvailable = await isUsingLocal()
if(checkCoin !== 'QORT' && !localNodeAvailable) throw new Error('Cannot send a non-QORT coin through the gateway. Please use your local node.')
const isGateway = await isRunningGateway()
if(checkCoin !== 'QORT' && isGateway) throw new Error('Cannot send a non-QORT coin through the gateway. Please use your local node.')
if (checkCoin === "QORT") {
// 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
@ -2789,4 +2823,60 @@ export const cancelSellOrder = async (data, isFromExtension) => {
} catch (error) {
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");
}
};