diff --git a/backend/contracts/IdentityAggregator.sol b/backend/contracts/IdentityAggregator.sol index ca57da0..141b7f4 100644 --- a/backend/contracts/IdentityAggregator.sol +++ b/backend/contracts/IdentityAggregator.sol @@ -2,9 +2,6 @@ pragma solidity ^0.8.0; import "hardhat/console.sol"; -// import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -// import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -// import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./VerifyJWT.sol"; @@ -14,29 +11,21 @@ contract IdentityAggregator is Ownable { mapping(string => address) public contractAddrForKeyword; // e.g., "orcid" => VerifyJWT(orcidContractAddress) - // Allows easier lookup for keywords // NOTE: Don't need this if our only accessor func is getAllAccounts() - mapping(string => string) private keywordForKeyword; + mapping(string => string) private keywordForKeyword; // Allows easier lookup for keywords - string[] private keywords; // e.g., "orcid" // TODO: Better name than 'keywords'?? + string[] private keywords; // e.g., "orcid" event AddSupportForContract(string contractKeyword); event RemoveSupportForContract(string contractKeyword); - constructor() { - - } - - /// @notice Add support for a new VerifyJWT contract. /// @param keyword The string used to denote the source of the JWT (e.g., "twitter"). /// @param contractAddress The address of the JWT contract to be supported. - function addPlatformContract(string memory keyword, address contractAddress) public onlyOwner { // TODO: there must be a better way than onlyOwner - + function addVerifyJWTContract(string calldata keyword, address contractAddress) public onlyOwner { // Require that neither this keyword nor this contract has been added - require(bytes(keywordForKeyword[keyword]).length == 0); - require(contractAddrForKeyword[keyword] == address(0)); + require(bytes(keywordForKeyword[keyword]).length == 0, "This keyword is already being used"); keywords.push(keyword); keywordForKeyword[keyword] = keyword; @@ -45,11 +34,10 @@ contract IdentityAggregator is Ownable { emit AddSupportForContract(keyword); } - // TODO: Is there a way to store keywords that allows iteration but allows removal without iteration? /// @notice Remove support for a VerifyJWT contract. /// @param keyword The string used to lookup the contract. - function removeSupportFor(string memory keyword) public onlyOwner { // TODO: there must be a better way than onlyOwner - require(contractAddrForKeyword[keyword] != address(0), "There is no corresponding contract for this keyword."); + function removeSupportFor(string calldata keyword) public onlyOwner { + require(contractAddrForKeyword[keyword] != address(0), "There is no corresponding contract for this keyword"); for (uint i = 0; i < keywords.length; i++) { if (keccak256(bytes(keywords[i])) == keccak256(bytes(keyword))) { @@ -81,37 +69,6 @@ contract IdentityAggregator is Ownable { return allCreds; } - // TODO: Either delete this function, or find a better implementation. - // e.g., keyword1 == "orcid", creds1 == "12345...", keyword2 == "twitter" ---> returns "@somehandle" - function getCredsFromCreds( - string memory keyword1, - bytes calldata creds1, // TODO: Make these parameters fixed-length - string memory keyword2 - ) - public returns (bytes memory creds2) { - - // Require that we have stored the contracts for the specified keywords - require(bytes(keywordForKeyword[keyword1]).length != 0); - require(bytes(keywordForKeyword[keyword2]).length != 0); - - // Get user address - address creds1ContractAddr = contractAddrForKeyword[keyword1]; - VerifyJWT creds1Contract = VerifyJWT(creds1ContractAddr); - address userAddr = creds1Contract.addressForCreds(creds1); - - string memory errorMessage = string(abi.encodePacked("This user has no creds for ", keyword1)); - require(userAddr != address(0), errorMessage); - - address creds2ContractAddr = contractAddrForKeyword[keyword2]; - VerifyJWT creds2Contract = VerifyJWT(creds2ContractAddr); - bytes memory creds2 = creds2Contract.credsForAddress(userAddr); - - errorMessage = string(abi.encodePacked("This user has no creds for ", keyword2)); - require(creds2.length != 0); - - return creds2; - } - function getKeywords() public view returns (string[] memory) { return keywords; } diff --git a/backend/test/identityAggregator.js b/backend/test/identityAggregator.js index 670c881..adbb05e 100644 --- a/backend/test/identityAggregator.js +++ b/backend/test/identityAggregator.js @@ -5,123 +5,134 @@ const { solidity } = require("ethereum-waffle"); const search64 = require('../../../whoisthis.wtf-frontend/src/searchForPlaintextInBase64.js'); // import { fixedBufferXOR as xor, sandwichIDWithBreadFromContract, padBase64, hexToString, searchForPlainTextInBase64 } from 'wtfprotocol-helpers'; const { hexToString } = require('wtfprotocol-helpers'); +const { + vmExceptionStr, + orcidKid, orcidBotomBread, orcidTopBread, + googleKid, googleBottomBread, googleTopBread, + deployVerifyJWTContract, + deployIdAggregator, + sha256FromString, + sandwichIDWithBreadFromContract, + jwksKeyToPubkey, +} = require('./utils/utils'); -// chai.use(solidity); - - -//-------------------- Constants & Helpers -------------------- - -const orcidKid = '7hdmdswarosg3gjujo8agwtazgkp1ojs' -const orcidBotomBread = '0x222c22737562223a22' -const orcidTopBread = '0x222c22617574685f74696d65223a' - -const deployVerifyJWTContract = async (...args) => { - let VJWT = await ethers.getContractFactory('VerifyJWT') - return await upgrades.deployProxy(VJWT, args, { - initializer: 'initialize', - }); -} - -const sha256FromString = x => ethers.utils.sha256(ethers.utils.toUtf8Bytes(x)) - -// Make sure it does bottomBread + id + topBread and does not allow any other text in between. If Google changes their JWT format so that the sandwich now contains other fields between bottomBread and topBread, this should fail until the contract is updated. -const sandwichIDWithBreadFromContract = async (id, contract) => { - let sandwich = (await contract.bottomBread()) + Buffer.from(id).toString('hex') + (await contract.topBread()); - sandwich = sandwich.replaceAll('0x', ''); - return sandwich -} - -// Converts JWKS RSAkey to e and n: -const jwksKeyToPubkey = (jwks) => { - let parsed = JSON.parse(jwks) - return [ - ethers.BigNumber.from(Buffer.from(parsed['e'], 'base64url')), - ethers.BigNumber.from(Buffer.from(parsed['n'], 'base64url')) - ] -} - -//------------------------------------------------- - - - -describe.only("IdentityAggregator", function () { - - // TODO: What's the best way to initialize contract variables before all tests, instead of initializing within every test? +describe("IdentityAggregator", function () { describe("keywords", function () { - before(async function () { - const IdentityAggregator = await ethers.getContractFactory("IdentityAggregator"); - this.idAggregator = await IdentityAggregator.deploy(); - await this.idAggregator.deployed(); + this.idAggregator = await deployIdAggregator(); }); it("Should be empty when contract is deployed", async function () { expect(await this.idAggregator.getKeywords()).to.be.an('array').that.is.empty; }); - it("Should be updated when support for a new contract is added", async function () { - //--------------------------- Set up context --------------------------- - // get mock vjwt contract address - const [owner] = await ethers.getSigners() - const transactionCount = await owner.getTransactionCount() - const verifyJWTAddress = getContractAddress({ - from: owner.address, - nonce: transactionCount - }) + it("Should include 'orcid' after support for orcid contract is added", async function () { const keyword = 'orcid'; - await this.idAggregator.addPlatformContract(keyword, verifyJWTAddress); + await this.idAggregator.addVerifyJWTContract(keyword, "0x100DEF1234567890ABCDEF1234567890ABCDE001"); + expect(await this.idAggregator.getKeywords()).to.include(keyword); + }); + + it("Should include 'google' after support for google contract is added", async function () { + const keyword = 'google'; + await this.idAggregator.addVerifyJWTContract(keyword, "0x200DEF1234567890ABCDEF1234567890ABCDE002"); + expect(await this.idAggregator.getKeywords()).to.include(keyword); + }); - //--------------------------- Run test --------------------------- + it("Should include both 'orcid' and 'google'", async function () { + const keywords = ['orcid', 'google']; + expect(await this.idAggregator.getKeywords()).to.have.members(keywords); + }); + + // Test deletion + it("Should not include 'orcid' after support for orcid contract is removed", async function () { + const keyword = 'orcid'; + await this.idAggregator.removeSupportFor(keyword); + expect(await this.idAggregator.getKeywords()).to.not.include(keyword); + }); + + it("Should not include 'google' after support for google contract is removed", async function () { + const keyword = 'google'; + await this.idAggregator.removeSupportFor(keyword); + expect(await this.idAggregator.getKeywords()).to.not.include(keyword); + }); - expect(await this.idAggregator.getKeywords()).to.have.members([keyword]); + // Test addition after deletion + it("Should include 'twitter' after support for twitter contract is added", async function () { + const keyword = 'twitter'; + await this.idAggregator.addVerifyJWTContract(keyword, "0x300DEF1234567890ABCDEF1234567890ABCDE003"); + expect(await this.idAggregator.getKeywords()).to.include(keyword); }); + }); describe("contractAddrForKeyword", function () { it("Should be updated when support for a new contract is added", async function () { - //--------------------------- Set up context --------------------------- - - const IdentityAggregator = await ethers.getContractFactory("IdentityAggregator"); - const idAggregator = await IdentityAggregator.deploy(); - await idAggregator.deployed(); + const idAggregator = await deployIdAggregator(); + const [owner] = await ethers.getSigners(); // get contract address for VerifyJWT - const [owner] = await ethers.getSigners() - const transactionCount = await owner.getTransactionCount() - const futureAddress = getContractAddress({ + const transactionCount = await owner.getTransactionCount(); + const vjwtAddress = getContractAddress({ from: owner.address, nonce: transactionCount - }) + }); vjwt = await deployVerifyJWTContract(11, 59, orcidKid, orcidBotomBread, orcidTopBread); const keyword = "orcid"; - await idAggregator.addPlatformContract(keyword, futureAddress); - - //--------------------------- Run test --------------------------- + await idAggregator.addVerifyJWTContract(keyword, vjwtAddress); const verifyJWTAddress = await idAggregator.callStatic.contractAddrForKeyword(keyword); - expect(verifyJWTAddress).to.equal(futureAddress); + expect(verifyJWTAddress).to.equal(vjwtAddress); + }); + }); + + describe("addVerifyJWTContract", function () { + before(async function () { + this.idAggregator = await deployIdAggregator(); + }); + + it("Should revert when attempting to use the keyword of an already supported contract", async function () { + const keyword = 'twitter'; + addr = '0x100DEF1234567890ABCDEF1234567890ABCDE001'; + await this.idAggregator.addVerifyJWTContract(keyword, addr); + addr = '0x200DEF1234567890ABCDEF1234567890ABCDE002'; + const funcStr = 'addVerifyJWTContract(string,address)'; + await expect(this.idAggregator[funcStr](keyword, addr)).to.be.revertedWith(vmExceptionStr + "'This keyword is already being used'"); + }); + }); + + describe("removeSupportFor", async function () { + // Try to remove an unsupported contract + it("Should revert ", async function () { + const idAggregator = await deployIdAggregator() + keyword = 'twitter'; + await idAggregator.addVerifyJWTContract(keyword, "0x100DEF1234567890ABCDEF1234567890ABCDE001"); + expect(await idAggregator.getKeywords()).to.include(keyword); + + keyword = "definitelynotthekeyword"; + const funcStr = 'removeSupportFor(string)'; + await expect(idAggregator[funcStr](keyword)).to.be.revertedWith(vmExceptionStr + "'There is no corresponding contract for this keyword'"); }); }); describe("getAllAccounts", function () { - it("Should return array of supported creds", async function() { - //--------------------------- Set up context --------------------------- + before(async function () { + this.idAggregator = await deployIdAggregator(); + }); - const IdentityAggregator = await ethers.getContractFactory("IdentityAggregator"); - const idAggregator = await IdentityAggregator.deploy(); - await idAggregator.deployed(); + it("Should return array of supported creds, the first of which is the correct orcid", async function() { + //--------------------------- Set up context --------------------------- + const [owner] = await ethers.getSigners(); // get contract address for VerifyJWT - const [owner] = await ethers.getSigners() - const transactionCount = await owner.getTransactionCount() + const transactionCount = await owner.getTransactionCount(); const vjwtAddress = getContractAddress({ from: owner.address, nonce: transactionCount - }) + }); const [eOrcid, nOrcid] = jwksKeyToPubkey('{"kty":"RSA","e":"AQAB","use":"sig","kid":"production-orcid-org-7hdmdswarosg3gjujo8agwtazgkp1ojs","n":"jxTIntA7YvdfnYkLSN4wk__E2zf_wbb0SV_HLHFvh6a9ENVRD1_rHK0EijlBzikb-1rgDQihJETcgBLsMoZVQqGj8fDUUuxnVHsuGav_bf41PA7E_58HXKPrB2C0cON41f7K3o9TStKpVJOSXBrRWURmNQ64qnSSryn1nCxMzXpaw7VUo409ohybbvN6ngxVy4QR2NCC7Fr0QVdtapxD7zdlwx6lEwGemuqs_oG5oDtrRuRgeOHmRps2R6gG5oc-JqVMrVRv6F9h4ja3UgxCDBQjOVT1BFPWmMHnHCsVYLqbbXkZUfvP2sO1dJiYd_zrQhi-FtNth9qrLLv3gkgtwQ"}'); const vjwt = await deployVerifyJWTContract(eOrcid, nOrcid, orcidKid, orcidBotomBread, orcidTopBread); @@ -143,17 +154,82 @@ describe.only("IdentityAggregator", function () { await vjwt.verifyMe(ethers.BigNumber.from(signature), message, payloadIdx, startIdx, endIdx, '0x'+sandwich); const keyword = "orcid"; - await idAggregator.addPlatformContract(keyword, vjwtAddress); + await this.idAggregator.addVerifyJWTContract(keyword, vjwtAddress); - const allAccounts = await idAggregator.callStatic.getAllAccounts(owner.address); + const allAccounts = await this.idAggregator.callStatic.getAllAccounts(owner.address); const creds = hexToString(allAccounts[0]); - console.log(creds) //--------------------------- Run test --------------------------- expect(creds).to.equal(correctID); }); + + it("Should return array of supported creds, the second of which is the correct gmail", async function() { + //--------------------------- Set up context --------------------------- + const [owner] = await ethers.getSigners(); + + // get contract address for VerifyJWT + const transactionCount = await owner.getTransactionCount(); + const vjwtAddress = getContractAddress({ + from: owner.address, + nonce: transactionCount + }); + + const [eGoogle, nGoogle] = jwksKeyToPubkey('{"alg":"RS256","use":"sig","n":"pFcwF2goSItvLhMJR1u0iPu2HO3wy6SSppmzgISWkRItInbuf2lWdQBt3x45mZsS9eXn6t9lUYnnduO5MrVtA1KoeZhHfSJZysIPh9S7vbU7_mV9SaHSyFPOOZr5jpU2LhNJehWqek7MTJ7FfUp1sgxtnUu-ffrFvMpodUW5eiNMcRmdIrd1O1--WlMpQ8sNk-KVTb8M8KPD0SYz-8kJLAwInUKK0EmxXjnYPfvB9RO8_GLAU7jodmTcVMD25PeA1NRvYqwzpJUYfhAUhPtE_rZX-wxn0udWddDQqihU7T_pTxiZe9R0rI0iAg--pV0f1dYnNfrZaB7veQq_XFfvKw","e":"AQAB","kty":"RSA","kid":"729189450d49028570425266f03e737f45af2932"}') + const vjwt = await deployVerifyJWTContract(eGoogle, nGoogle, googleKid, googleBottomBread, googleTopBread); + + // Set up context to call commitJWTProof() and verifyMe() + const idToken = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjcyOTE4OTQ1MGQ0OTAyODU3MDQyNTI2NmYwM2U3MzdmNDVhZjI5MzIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiMjU0OTg0NTAwNTY2LTNxaXM1NG1vZmVnNWVkb2dhdWpycDhyYjdwYnA5cXRuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiMjU0OTg0NTAwNTY2LTNxaXM1NG1vZmVnNWVkb2dhdWpycDhyYjdwYnA5cXRuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTAwNzg3ODQ0NDczMTcyMjk4NTQzIiwiZW1haWwiOiJuYW5ha25paGFsQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoiMDREZXRTaGNSYUE4OWxlcEQzdWRnUSIsIm5hbWUiOiJOYW5hayBOaWhhbCBLaGFsc2EiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKdzRnMVA3UFZUS2ZWUU1ldFdtUVgxQlNvWjlPWTRVUWtLcjdsTDQ9czk2LWMiLCJnaXZlbl9uYW1lIjoiTmFuYWsgTmloYWwiLCJmYW1pbHlfbmFtZSI6IktoYWxzYSIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNjQ3NjYzNDk4LCJleHAiOjE2NDc2NjcwOTgsImp0aSI6IjE4ZmRmMGQ2M2VhYjI4YjRlYmY0NmFiMDMzZTM5OTU3NmE5MTJlZGUifQ.YqmOub03zNmloAcFvZE0E-4Gt2Y5fr_9XQLUYqXQ24X_GJaJh0HSQXouJeSXjnk8PT6E1FnPd89QAgwDvE_qxAoOvW7VKDycVapOeDtKdTQ-QpAn-ExE0Pvqgx1iaGRZFDS4DWESX1ZsQIBAB_MHK_ZFdAnOjeFzImuMkB1PZLY99przSaM8AEyvWn8wfEgdmkdoJERBXF7xJI2dfA9mTRjlQvhSC4K060bTJbUYug4sQLrvo53CsDjvXRnodnCB81EVWZUbf5B9dG__kebI3AjedKUcPb2wofpX_B7uAyVlD7Au3APEbZP7Asle0Bi76hDNGPQbLvR_nGWLoySfCQ'; + const correctID = 'nanaknihal@gmail.com'; + const [headerRaw, payloadRaw, signatureRaw] = idToken.split('.'); + const signature = Buffer.from(signatureRaw, 'base64url'); + const message = headerRaw + '.' + payloadRaw; + const payloadIdx = Buffer.from(headerRaw).length + 1; //Buffer.from('.').length == 1 + const sandwich = await sandwichIDWithBreadFromContract(correctID, vjwt); + const [startIdx, endIdx] = search64.searchForPlainTextInBase64(Buffer.from(sandwich, 'hex').toString(), payloadRaw); + const hashedMessage = sha256FromString(message); + const proof = ethers.utils.sha256(await vjwt.XOR(hashedMessage, owner.address)); + + await vjwt.commitJWTProof(proof); + await ethers.provider.send('evm_mine'); + await vjwt.verifyMe(ethers.BigNumber.from(signature), message, payloadIdx, startIdx, endIdx, '0x'+sandwich); + + const keyword = "google"; + await this.idAggregator.addVerifyJWTContract(keyword, vjwtAddress); + + const allAccounts = await this.idAggregator.callStatic.getAllAccounts(owner.address); + const creds = hexToString(allAccounts[1]); + + //--------------------------- Run test --------------------------- + + expect(creds).to.equal(correctID); + }); + + it("Should return the correct array of supported creds", async function() { + const [owner] = await ethers.getSigners(); + const allAccounts = await this.idAggregator.callStatic.getAllAccounts(owner.address); + const credsArray = allAccounts.map(creds => hexToString(creds)); + + expect(credsArray).to.include.members(['nanaknihal@gmail.com', '0000-0002-2308-9517']); + }); + + it("Should return an array that includes gmail but not orcid", async function() { + await this.idAggregator.removeSupportFor('orcid'); + const [owner] = await ethers.getSigners(); + const allAccounts = await this.idAggregator.callStatic.getAllAccounts(owner.address); + const credsArray = allAccounts.map(creds => hexToString(creds)); + + expect(credsArray).to.not.include.members(['0000-0002-2308-9517']); + }); + + it("Should return an array that includes neither orcid nor gmail", async function() { + await this.idAggregator.removeSupportFor('google'); + const [owner] = await ethers.getSigners(); + const allAccounts = await this.idAggregator.callStatic.getAllAccounts(owner.address); + const credsArray = allAccounts.map(creds => hexToString(creds)); + + expect(credsArray).to.not.include.members(['nanaknihal@gmail.com', '0000-0002-2308-9517']); + }); }); }); - diff --git a/backend/test/utils/utils.js b/backend/test/utils/utils.js new file mode 100644 index 0000000..e0bd628 --- /dev/null +++ b/backend/test/utils/utils.js @@ -0,0 +1,46 @@ +const { ethers } = require('hardhat'); + +exports.vmExceptionStr = 'VM Exception while processing transaction: reverted with reason string '; + +exports.orcidKid = '7hdmdswarosg3gjujo8agwtazgkp1ojs'; +exports.orcidBotomBread = '0x222c22737562223a22'; +exports.orcidTopBread = '0x222c22617574685f74696d65223a'; + +exports.googleKid = '729189450d49028570425266f03e737f45af2932' +exports.googleBottomBread = '0x222c22656d61696c223a22' +exports.googleTopBread = '0x222c22656d61696c5f7665726966696564223a' + +exports.deployVerifyJWTContract = async (...args) => { + let VJWT = await ethers.getContractFactory('VerifyJWT') + return await upgrades.deployProxy(VJWT, args, { + initializer: 'initialize', + }); +} + +exports.deployIdAggregator = async () => { + const IdentityAggregator = await ethers.getContractFactory("IdentityAggregator"); + const idAggregator = await IdentityAggregator.deploy(); + await idAggregator.deployed(); + return idAggregator; +} + +// input: x (string); output: keccak256 of string +exports.sha256FromString = x => ethers.utils.sha256(ethers.utils.toUtf8Bytes(x)) +// input: x (string); output: sha256 of string +exports.keccak256FromString = x => ethers.utils.keccak256(ethers.utils.toUtf8Bytes(x)) + +// Make sure it does bottomBread + id + topBread and does not allow any other text in between. If Google changes their JWT format so that the sandwich now contains other fields between bottomBread and topBread, this should fail until the contract is updated. +exports.sandwichIDWithBreadFromContract = async (id, contract) => { + let sandwich = (await contract.bottomBread()) + Buffer.from(id).toString('hex') + (await contract.topBread()); + sandwich = sandwich.replaceAll('0x', ''); + return sandwich +} + +// Converts JWKS RSAkey to e and n: +exports.jwksKeyToPubkey = (jwks) => { + let parsed = JSON.parse(jwks) + return [ + ethers.BigNumber.from(Buffer.from(parsed['e'], 'base64url')), + ethers.BigNumber.from(Buffer.from(parsed['n'], 'base64url')) + ] +} \ No newline at end of file diff --git a/backend/test/verifyjwt.js b/backend/test/verifyjwt.js index 92e390e..55a9662 100644 --- a/backend/test/verifyjwt.js +++ b/backend/test/verifyjwt.js @@ -2,37 +2,20 @@ const { expect } = require('chai'); const { ethers, upgrades } = require('hardhat'); const search64 = require('../../../whoisthis.wtf-frontend/src/searchForPlaintextInBase64.js'); -// input: x (string); output: keccak256 of string -const sha256FromString = x => ethers.utils.sha256(ethers.utils.toUtf8Bytes(x)) -// input: x (string); output: sha256 of string -const keccak256FromString = x => ethers.utils.keccak256(ethers.utils.toUtf8Bytes(x)) - -const orcidKid = '7hdmdswarosg3gjujo8agwtazgkp1ojs' -const orcidBotomBread = '0x222c22737562223a22' -const orcidTopBread = '0x222c22617574685f74696d65223a' - -const googleKid = '729189450d49028570425266f03e737f45af2932' -const googleBottomBread = '0x222c22656d61696c223a22' -const googleTopBread = '0x222c22656d61696c5f7665726966696564223a' - -// Converts JWKS RSAkey to e and n: -const jwksKeyToPubkey = (jwks) => { - let parsed = JSON.parse(jwks) - return [ - ethers.BigNumber.from(Buffer.from(parsed['e'], 'base64url')), - ethers.BigNumber.from(Buffer.from(parsed['n'], 'base64url')) - ] -} +const { + orcidKid, orcidBotomBread, orcidTopBread, + googleKid, googleBottomBread, googleTopBread, + deployVerifyJWTContract, + sha256FromString, + keccak256FromString, + sandwichIDWithBreadFromContract, + jwksKeyToPubkey, +} = require('./utils/utils'); + const [eOrcid, nOrcid] = jwksKeyToPubkey('{"kty":"RSA","e":"AQAB","use":"sig","kid":"production-orcid-org-7hdmdswarosg3gjujo8agwtazgkp1ojs","n":"jxTIntA7YvdfnYkLSN4wk__E2zf_wbb0SV_HLHFvh6a9ENVRD1_rHK0EijlBzikb-1rgDQihJETcgBLsMoZVQqGj8fDUUuxnVHsuGav_bf41PA7E_58HXKPrB2C0cON41f7K3o9TStKpVJOSXBrRWURmNQ64qnSSryn1nCxMzXpaw7VUo409ohybbvN6ngxVy4QR2NCC7Fr0QVdtapxD7zdlwx6lEwGemuqs_oG5oDtrRuRgeOHmRps2R6gG5oc-JqVMrVRv6F9h4ja3UgxCDBQjOVT1BFPWmMHnHCsVYLqbbXkZUfvP2sO1dJiYd_zrQhi-FtNth9qrLLv3gkgtwQ"}') const [eGoogle, nGoogle] = jwksKeyToPubkey('{"alg":"RS256","use":"sig","n":"pFcwF2goSItvLhMJR1u0iPu2HO3wy6SSppmzgISWkRItInbuf2lWdQBt3x45mZsS9eXn6t9lUYnnduO5MrVtA1KoeZhHfSJZysIPh9S7vbU7_mV9SaHSyFPOOZr5jpU2LhNJehWqek7MTJ7FfUp1sgxtnUu-ffrFvMpodUW5eiNMcRmdIrd1O1--WlMpQ8sNk-KVTb8M8KPD0SYz-8kJLAwInUKK0EmxXjnYPfvB9RO8_GLAU7jodmTcVMD25PeA1NRvYqwzpJUYfhAUhPtE_rZX-wxn0udWddDQqihU7T_pTxiZe9R0rI0iAg--pV0f1dYnNfrZaB7veQq_XFfvKw","e":"AQAB","kty":"RSA","kid":"729189450d49028570425266f03e737f45af2932"}') -const deployVerifyJWTContract = async (...args) => { - let VJWT = await ethers.getContractFactory('VerifyJWT') - return await upgrades.deployProxy(VJWT, args, { - initializer: 'initialize', - }); -} // describe('Integration test 2', function () { // it('Go through full process and make sure it success with a correct JWT', async function () { @@ -180,13 +163,6 @@ describe('proof of prior knowledge', function () { }); }); -// Make sure it does bottomBread + id + topBread and does not allow any other text in between. If Google changes their JWT format so that the sandwich now contains other fields between bottomBread and topBread, this should fail until the contract is updated. -async function sandwichIDWithBreadFromContract(id, contract){ - let sandwich = (await contract.bottomBread()) + Buffer.from(id).toString('hex') + (await contract.topBread()); - sandwich = sandwich.replaceAll('0x', ''); - return sandwich -} - describe('Frontend sandwiching', function(){ it('Test that correct sandwich is given for a specific ID', async function(){ let vjwt = await deployVerifyJWTContract(50,100, orcidKid, orcidBotomBread, orcidTopBread);