From c8df0d6e04664762946a9c0c832e85526b62132a Mon Sep 17 00:00:00 2001 From: Peter Salomonsen Date: Tue, 26 Dec 2023 09:44:13 +0100 Subject: [PATCH] support access for implicit accounts --- nearcontract/buildanddeploy.sh | 13 ++++--------- server/checkpermission.js | 28 +++++++++++++++++----------- server/checkpermission.spec.js | 26 +++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/nearcontract/buildanddeploy.sh b/nearcontract/buildanddeploy.sh index c883858..d958a82 100755 --- a/nearcontract/buildanddeploy.sh +++ b/nearcontract/buildanddeploy.sh @@ -5,12 +5,7 @@ RUSTFLAGS='-C link-arg=-s' cargo build --target=wasm32-unknown-unknown --release # Remove unneeded WebAssembly exports mkdir -p out cp ./target/wasm32-unknown-unknown/release/rust_simple_access_control.wasm out/main.wasm -if [ -z "$1" ] -then - echo "Deploying to DEV account" - near dev-deploy out/main.wasm -else - # Deploy to account given in argument to this script - echo "Deploying to $1" - near deploy $1 out/nft.wasm -fi +echo "Deploying to DEV account" +near dev-deploy out/main.wasm +near call `cat neardev/dev-account` --accountId=`cat neardev/dev-account` init + diff --git a/server/checkpermission.js b/server/checkpermission.js index 3ecd9ae..7e49b52 100644 --- a/server/checkpermission.js +++ b/server/checkpermission.js @@ -80,17 +80,23 @@ export async function checkPermission(repository, token) { } const account = await near.account(msgobj.accountId); - const accesskeys = await account.getAccessKeys(); - - const publicKeys = accesskeys.map(key => - nearApi.utils.PublicKey.fromString(key.public_key) - ); - - const pubkey = publicKeys.find(pk => - nacl.sign.detached.verify(new Uint8Array(sha256.array(msgbytes)), - new Uint8Array(signature), new Uint8Array(pk.data)) - ); - + let pubkey; + if (msgobj.accountId.length == 64) { + pubkey = new Uint8Array(32); + for (let i = 0; i < pubkey.length; i++) { + pubkey[i] = parseInt(msgobj.accountId.substr(i * 2, 2), 16); + } + } else { + const accesskeys = await account.getAccessKeys(); + const publicKeys = accesskeys.map(key => + nearApi.utils.PublicKey.fromString(key.public_key) + ); + + pubkey = publicKeys.find(pk => + nacl.sign.detached.verify(new Uint8Array(sha256.array(msgbytes)), + new Uint8Array(signature), new Uint8Array(pk.data)) + ); + } if (pubkey) { const contract = new nearApi.Contract(account, nearconfig.contractName, diff --git a/server/checkpermission.spec.js b/server/checkpermission.spec.js index 0308daa..7d9e729 100644 --- a/server/checkpermission.spec.js +++ b/server/checkpermission.spec.js @@ -1,5 +1,6 @@ import { checkPermission, PERMISSION_READER, PERMISSION_CONTRIBUTOR, use_testnet, PERMISSION_OWNER } from './checkpermission.js'; import { default as nearApi } from 'near-api-js'; +import { default as nacl } from 'tweetnacl'; import { homedir } from 'os'; import * as assert from 'assert'; import { readFileSync } from 'fs'; @@ -26,6 +27,8 @@ async function setUpTestConnection() { describe('checkpermission', function () { this.timeout(20000); + const reponame = 'test2'; + it('should allow anonymous reads for the default test repository', async () => { assert.equal((await checkPermission('test', 'ANONYMOUS')).permission, PERMISSION_READER); }); @@ -33,7 +36,6 @@ describe('checkpermission', function () { const near = await setUpTestConnection(); const testAccount = await near.account(testAccountName); - const reponame = 'test2'; await testAccount.functionCall({ contractId: testAccount.accountId, methodName: 'set_permission', @@ -52,4 +54,26 @@ describe('checkpermission', function () { const accessToken = tokenMessage + '.' + Buffer.from(signature.signature).toString('base64'); assert.equal((await checkPermission(reponame, accessToken)).permission, PERMISSION_OWNER); }); + it('should check access for implicit accounts', async () => { + const implicitAccountId = '3e393bf74cf63cf8e3851ea0fe6a92e56595f506947d7c66310e6ceac97a3e9f'; + const near = await setUpTestConnection(); + const testAccount = await near.account(testAccountName); + await testAccount.functionCall({ + contractId: testAccount.accountId, + methodName: 'set_permission', + args: { + path: reponame, + account_id: implicitAccountId, + permission: PERMISSION_CONTRIBUTOR + }, + attachedDeposit: '100000000000000000000000' + }); + const privateKey = new Uint8Array([254, 114, 130, 212, 33, 69, 193, 93, 12, 15, 108, 76, 19, 198, 118, 148, 193, 62, 78, 4, 9, 157, 188, 191, 132, 137, 188, 31, 54, 103, 246, 191, 62, 57, 59, 247, 76, 246, 60, 248, 227, 133, 30, 160, 254, 106, 146, 229, 101, 149, 245, 6, 148, 125, 124, 102, 49, 14, 108, 234, 201, 122, 62, 159]); + + const tokenMessage = btoa(JSON.stringify({ accountId: implicitAccountId, iat: new Date().getTime() })); + const signature = nacl.sign.detached(new TextEncoder().encode(tokenMessage), privateKey); + const accessToken = tokenMessage + '.' + btoa(String.fromCharCode(...signature)); + + assert.equal((await checkPermission(reponame, accessToken)).permission, PERMISSION_CONTRIBUTOR); + }); }); \ No newline at end of file