diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 000000000..4560bffa4 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,30 @@ +name: Pull request + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16.15.1 + - run: yarn install + - run: yarn build + publish: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 16.15.1 + registry-url: https://registry.npmjs.org/ + - run: yarn install + - run: yarn build + - run: yarn publish + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} diff --git a/index.html b/index.html index 1963bf668..74c612637 100644 --- a/index.html +++ b/index.html @@ -31,6 +31,8 @@

Hello, Snaps!

+ + diff --git a/package.json b/package.json index 831df1a04..b07557510 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ }, "devDependencies": { "@metamask/snaps-cli": "^0.18.1", + "@metamask/providers": "^9.0.0", "@types/node": "^17.0.18", "rimraf": "^3.0.2", "ts-node": "^10.5.0", diff --git a/snap.manifest.json b/snap.manifest.json index 907acefbf..d2dd6c11b 100644 --- a/snap.manifest.json +++ b/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/blockchain-lab-um/ssi-snap.git" }, "source": { - "shasum": "KeyOvYHaNPZj76J1WrMKvCNdiB+/sJ0DlMDbPNkxSEU=", + "shasum": "EBoU/jgioFgxClhncL9EE8q3PJB2rqV23ylYTYxgT7o=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/src/index.ts b/src/index.ts index 1b8d712d1..58bd0f01c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,10 @@ -import { Wallet } from "./interfaces"; import { VerifiableCredential } from "@veramo/core"; -import { get_id, list_vcs, save_vc, create_vp } from "./utils/veramo_utils"; -import { changeInfuraToken } from "./utils/snap_utils"; -import { getConfig } from "./utils/state_utils"; import { OnRpcRequestHandler } from "@metamask/snap-types"; +import { togglePopups, changeInfuraToken } from "./rpc/configure"; +import { getVCs } from "./rpc/getVCs"; +import { getVP } from "./rpc/getVP"; +import { saveVC } from "./rpc/saveVC"; -declare let wallet: Wallet; let vc_id: string; let vc: VerifiableCredential; let challenge: string; @@ -29,98 +28,20 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ if (request.params) { querry = (request as any).params[0]; } - console.log("querry", querry); - let vcs = await list_vcs(querry); - let num = vcs.length; - - //TODO display specific VCs - const result = await wallet.request({ - method: "snap_confirm", - params: [ - { - prompt: `Send VCs`, - description: "Are you sure you want to send VCs to the dApp?", - textAreaContent: - "Some dApps are less secure than others and could save data from VCs against your will. Be careful where you send your private VCs! Number of VCs submitted is " + - num, - }, - ], - }); - if (result) { - return { data: vcs }; - } else { - return { error: "User rejected" }; - } - case "getDIDAddress": - let did = await get_id(); - if (did != null) { - return { data: did.did.split(":")[3] }; - } - return { data: false, error: "Failed to fetch addres" }; + return await getVCs(querry); case "saveVC": vc = (request as any).params[0]; - if (vc) { - const result = await wallet.request({ - method: "snap_confirm", - params: [ - { - prompt: `Save VC`, - description: "Would you like to save the following VC?", - textAreaContent: JSON.stringify(vc.credentialSubject), - }, - ], - }); - if (result) { - await save_vc(vc); - return { data: true }; - } else { - return { data: false, error: "Request declined" }; - } - } else { - console.log("Missing parameters: vc"); - return { error: "Missing parameter: vc" }; - } + return await saveVC(vc); case "getVP": vc_id = (request as any).params[0]; domain = (request as any).params[1]; challenge = (request as any).params[2]; - console.log(vc_id, domain, challenge); - if (vc_id) { - let vp = await create_vp(vc_id, challenge, domain); - return { data: vp }; - } else { - console.log("Missing parameters: vc_id"); - return { error: "Missing parameter: vc_id" }; - } + return await getVP(vc_id, domain, challenge); case "changeInfuraToken": infuraToken = (request as any).params[0]; - if (infuraToken != null && infuraToken != "") { - const config = await getConfig(); - const result = await wallet.request({ - method: "snap_confirm", - params: [ - { - prompt: `Change Infura Token`, - description: - "Would you like to change the infura token to following?", - textAreaContent: - "Current token: " + - config.infuraToken + - "\n" + - "New token: " + - infuraToken, - }, - ], - }); - if (result) { - await changeInfuraToken(infuraToken); - return { data: true }; - } else { - return { data: false, error: "Request declined" }; - } - } else { - return { error: "Missing parameter: infuraToken" }; - } + return await changeInfuraToken(infuraToken); + case "togglePopups": + return await togglePopups(); default: throw new Error("Method not found."); } diff --git a/src/interfaces.ts b/src/interfaces.ts index c741625c5..8090c2da6 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -7,17 +7,6 @@ import { SnapPrivateKeyStore, } from "./veramo/plugins/snapDataStore/snapDataStore"; -/** - * MetaMask Wallet interface - */ -export interface Wallet { - registerApiRequestHandler: (origin: unknown) => unknown; - registerRpcMessageHandler: (origin: unknown) => unknown; - request: (origin: any) => unknown; - send(options: { method: string; params: unknown[] }): unknown; - getAppKey(): Promise; -} - /** * MetaMask State */ @@ -57,14 +46,23 @@ export type ExtendedVerifiableCredential = VerifiableCredential & { }; export interface SSISnapConfig { - /** - * Type of store, 'snap' by default - */ - store: string; - /** - * Infura token, used by Veramo agent. - */ - infuraToken: string; + veramo: { + /** + * Type of store, 'snap' by default + */ + store: string; + /** + * Infura token, used by Veramo agent. + */ + infuraToken: string; + /** + * + */ + }; + dApp: { + disablePopups: boolean; + friendlyDapps: Array; + }; } /** diff --git a/src/rpc/configure.ts b/src/rpc/configure.ts new file mode 100644 index 000000000..1545bbf04 --- /dev/null +++ b/src/rpc/configure.ts @@ -0,0 +1,67 @@ +import { Response } from "./../interfaces"; +import { + _changeInfuraToken, + _togglePopups, + _addFriendlyDapp, + _getFriendlyDapps, + _removeFriendlyDapp, +} from "./../utils/snap_utils"; +import { getConfig } from "./../utils/state_utils"; + +export async function togglePopups(): Promise { + const config = await getConfig(); + + const result = + config.dApp.disablePopups || + (await wallet.request({ + method: "snap_confirm", + params: [ + { + prompt: `Toggle Popups`, + description: "Would you like to toggle the popups to following?", + textAreaContent: + "Current setting: " + + config.dApp.disablePopups + + "\n" + + "New setting: " + + !config.dApp.disablePopups, + }, + ], + })); + if (result) { + await await _togglePopups(); + return { data: true }; + } else { + return { data: false, error: "Request declined" }; + } +} + +export async function changeInfuraToken(token?: string): Promise { + if (token != null && token != "") { + const config = await getConfig(); + const result = await wallet.request({ + method: "snap_confirm", + params: [ + { + prompt: `Change Infura Token`, + description: + "Would you like to change the infura token to following?", + textAreaContent: + "Current token: " + + config.veramo.infuraToken + + "\n" + + "New token: " + + token, + }, + ], + }); + if (result) { + await _changeInfuraToken(token); + return { data: true }; + } else { + return { data: false, error: "Request declined" }; + } + } else { + return { error: "Missing parameter: infuraToken" }; + } +} diff --git a/src/rpc/getVCs.ts b/src/rpc/getVCs.ts new file mode 100644 index 000000000..d5ddb3046 --- /dev/null +++ b/src/rpc/getVCs.ts @@ -0,0 +1,30 @@ +import { list_vcs } from "../utils/veramo_utils"; +import { Response } from "../interfaces"; +import { getConfig } from "../utils/state_utils"; + +export async function getVCs(querry?: any): Promise { + console.log("querry", querry); + let vcs = await list_vcs(querry); + const config = await getConfig(); + console.log("VCs: ", vcs); + + const result = + config.dApp.disablePopups || + (await wallet.request({ + method: "snap_confirm", + params: [ + { + prompt: `Send VCs`, + description: "Are you sure you want to send VCs to the dApp?", + textAreaContent: + "Some dApps are less secure than others and could save data from VCs against your will. Be careful where you send your private VCs! Number of VCs submitted is " + + vcs.length, + }, + ], + })); + if (result) { + return { data: { vcs: vcs } }; + } else { + return { error: "User rejected" }; + } +} diff --git a/src/rpc/getVP.ts b/src/rpc/getVP.ts new file mode 100644 index 000000000..90b90d7ad --- /dev/null +++ b/src/rpc/getVP.ts @@ -0,0 +1,11 @@ +import { create_vp } from "../utils/veramo_utils"; + +export async function getVP(vc_id: string, domain: string, challenge: string) { + if (vc_id) { + let vp = await create_vp(vc_id, challenge, domain); + return { data: vp }; + } else { + console.log("Missing parameters: vc_id"); + return { error: "Missing parameter: vc_id" }; + } +} diff --git a/src/rpc/saveVC.ts b/src/rpc/saveVC.ts new file mode 100644 index 000000000..be89f5eff --- /dev/null +++ b/src/rpc/saveVC.ts @@ -0,0 +1,26 @@ +import { VerifiableCredential } from "@veramo/core"; +import { save_vc } from "../utils/veramo_utils"; + +export async function saveVC(vc?: VerifiableCredential) { + if (vc) { + const result = await wallet.request({ + method: "snap_confirm", + params: [ + { + prompt: `Save VC`, + description: "Would you like to save the following VC?", + textAreaContent: JSON.stringify(vc.credentialSubject), + }, + ], + }); + if (result) { + await save_vc(vc); + return { data: true }; + } else { + return { data: false, error: "Request declined" }; + } + } else { + console.log("Missing parameters: vc"); + return { error: "Missing parameter: vc" }; + } +} diff --git a/src/utils/snap_utils.ts b/src/utils/snap_utils.ts index d207c04e9..6e19ac898 100644 --- a/src/utils/snap_utils.ts +++ b/src/utils/snap_utils.ts @@ -30,9 +30,48 @@ export async function getCurrentAccount(): Promise { * * @param token infura token */ -export async function changeInfuraToken(token: string) { +export async function _changeInfuraToken(token: string) { let config = await getConfig(); - config.infuraToken = token; + config.veramo.infuraToken = token; await updateConfig(config); return; } +/** + * Function that toggles the disablePopups flag in the config. + * + */ +export async function _togglePopups() { + let config = await getConfig(); + config.dApp.disablePopups = !config.dApp.disablePopups; + await updateConfig(config); + return; +} +/** + * Function that lets you add a friendly dApp + */ +export async function _addFriendlyDapp(dapp: string) { + let config = await getConfig(); + config.dApp.friendlyDapps.push(dapp); + await updateConfig(config); + return; +} +/** + * Function that removes a friendly dApp. + * + */ +export async function _removeFriendlyDapp(dapp: string) { + let config = await getConfig(); + config.dApp.friendlyDapps = config.dApp.friendlyDapps.filter( + (d) => d !== dapp + ); + await updateConfig(config); + return; +} +/** + * Function that returns a list of friendly dApps. + * + */ +export async function _getFriendlyDapps(): Promise> { + let config = await getConfig(); + return config.dApp.friendlyDapps; +} diff --git a/src/utils/state_utils.ts b/src/utils/state_utils.ts index 3895a7ab7..488911992 100644 --- a/src/utils/state_utils.ts +++ b/src/utils/state_utils.ts @@ -1,12 +1,10 @@ import { - Wallet, State, SSISnapState, SSIAccountState, SSISnapConfig, } from "../interfaces"; import { getCurrentAccount } from "./snap_utils"; -declare let wallet: Wallet; /** * Internal function for updating SSISnapState object in the MetaMask state @@ -93,8 +91,14 @@ export async function getConfig(): Promise { return ssiSnapState.config; } else { const config = { - infuraToken: "6e751a2e5ff741e5a01eab15e4e4a88b", - store: "snap", + dApp: { + disablePopups: false, + friendlyDapps: [], + }, + veramo: { + infuraToken: "6e751a2e5ff741e5a01eab15e4e4a88b", + store: "snap", + }, } as SSISnapConfig; await updateConfig(config); return config; diff --git a/src/utils/veramo_utils.ts b/src/utils/veramo_utils.ts index cd46c0c7e..14a1e6b75 100644 --- a/src/utils/veramo_utils.ts +++ b/src/utils/veramo_utils.ts @@ -6,7 +6,7 @@ import { VerifiablePresentation, } from "@veramo/core"; import { getCurrentAccount } from "./snap_utils"; -import { getVCAccount } from "./state_utils"; +import { getConfig } from "./state_utils"; declare let wallet: any; /** @@ -46,7 +46,7 @@ export async function list_vcs( const agent = await getAgent(); const vcs = await agent.listVCS(querry); console.log("VCS", vcs); - return vcs; + return vcs.vcs; } /** @@ -62,17 +62,21 @@ export async function create_vp( let identifier = await importMetaMaskAccount(); const agent = await getAgent(); const vc = await agent.getVC({ id: vc_id }); + const config = await getConfig(); + console.log(vc_id, domain, challenge); if (vc.vc != null) { - const result = await wallet.request({ - method: "snap_confirm", - params: [ - { - prompt: `Alert`, - description: "Do you wish to create a VP from the following VC?", - textAreaContent: JSON.stringify(vc.vc.credentialSubject), - }, - ], - }); + const result = + config.dApp.disablePopups || + (await wallet.request({ + method: "snap_confirm", + params: [ + { + prompt: `Alert`, + description: "Do you wish to create a VP from the following VC?", + textAreaContent: JSON.stringify(vc.vc.credentialSubject), + }, + ], + })); console.log("RESULT", result); console.log("VC", vc); if (result) { @@ -136,65 +140,3 @@ export const importMetaMaskAccount = async (): Promise => { }); return did; }; - -// export async function create_vc() { -// const agent = await getAgent(); -// const acc = await getVCAccount(); -// console.log("Account state", acc); - -// const id = await agent.didManagerCreate({ -// provider: "snap", -// }); - -// //const account = await getCurrentAccount(); -// // let did = "did:ethr:0x4:" + account; -// // // const controllerKeyId = `metamask-${account}`; -// // // await agent.didManagerImport({ -// // // did, -// // // provider: "metamask", -// // // controllerKeyId, -// // // keys: [ -// // // { -// // // kid: controllerKeyId, -// // // type: "Secp256k1", -// // // kms: "web3", -// // // privateKeyHex: "", -// // // meta: { -// // // provider: "metamask", -// // // account: account.toLocaleLowerCase(), -// // // algorithms: ["eth_signMessage", "eth_signTypedData"], -// // // }, -// // // } as MinimalImportableKey, -// // // ], -// // // }); - -// const identifiers = await agent.didManagerFind(); - -// if (identifiers.length > 0) { -// identifiers.map((id: any) => { -// console.log(id); -// console.log(".................."); -// }); -// } -// // console.log("Resolving did..."); -// //const result = await agent.resolveDid({ didUrl: did }); - -// const result = await agent.createVerifiableCredential({ -// credential: { -// issuer: { id: id.did }, -// "@context": [ -// "https://www.w3.org/2018/credentials/v1", -// "https://example.com/1/2/3", -// ], -// type: ["VerifiableCredential", "Custom"], -// issuanceDate: new Date().toISOString(), -// credentialSubject: { -// id: "did:web:example.com", -// you: "Rock", -// }, -// }, -// proofFormat: "EthereumEip712Signature2021", -// }); -// console.log("RESULT", result); -// return result; -// } diff --git a/src/veramo/setup.ts b/src/veramo/setup.ts index 18d13134c..576b832c7 100644 --- a/src/veramo/setup.ts +++ b/src/veramo/setup.ts @@ -44,7 +44,7 @@ declare let wallet: any; export const getAgent = async (): Promise => { let config = await getConfig(); - let INFURA_PROJECT_ID = config.infuraToken; + let INFURA_PROJECT_ID = config.veramo.infuraToken; console.log("INFURA_PROJECT_ID", INFURA_PROJECT_ID); const web3Providers: Record = {};