Skip to content

Added address Verification #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cf5561b
Added address verification check
Nov 24, 2021
8fe3bf5
Version bump
gavinharris-dev Nov 24, 2021
6173f04
Fixed some bugs in verify
Nov 24, 2021
053964d
Merge branch 'main' of github.com:gavinharris-dev/web3-cardano-token
Nov 24, 2021
072ae8f
Merge branch 'pyropy:main' into main
gavinharris-dev Jan 22, 2022
33303ca
Updated for Review Comments
gavinharris-dev Jan 22, 2022
b457038
CIP30 changes
Feb 22, 2022
d209c8c
Merge branch 'main' into feature/cip30
gavinharris-dev Feb 22, 2022
6e686e6
Merge pull request #1 from gavinharris-dev/feature/cip30
gavinharris-dev Feb 22, 2022
f78a184
Bumpped version
Feb 23, 2022
83282d4
Merge branch 'feature/cip30' of github.com:gavinharris-dev/web3-carda…
Feb 23, 2022
19bb462
Merge pull request #2 from gavinharris-dev/feature/cip30
gavinharris-dev Feb 23, 2022
da1dc9b
RewardAddress is not a standalone Object!
Mar 8, 2022
8d3f6be
Merge pull request #3 from gavinharris-dev/feature/cip30
gavinharris-dev Mar 8, 2022
ed9b2a1
Check this out.
Mar 15, 2022
271a125
Merge pull request #4 from gavinharris-dev/feature/cip30
gavinharris-dev Mar 15, 2022
2c9bb35
Fix issue with Verification. There are still lots to fix; if only I c…
Mar 15, 2022
a619850
Fix issue with Verification. There are still lots to fix; if only I c…
Mar 15, 2022
f6e276c
wsdfg
Aug 24, 2022
2cc72b2
sdfds
Aug 24, 2022
f39848c
sdfds
Aug 24, 2022
daebc6a
Validate Stake Address validation
gavinharris-dev Jan 11, 2023
3e68824
Update package.json
gavinharris-dev Jan 11, 2023
f613fcc
Validate Stake Address validation
gavinharris-dev Jan 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ignore artifacts:
dist
1 change: 1 addition & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Binary file added dist/01d712ed3b6fe8f23933.module.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions dist/228.browser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/351.browser.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/405.browser.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/603.browser.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/66.browser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/891.browser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/997.browser.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions dist/browser.js

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions dist/browser.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/

/*! https://mths.be/base64 v1.0.0 by @mathias | MIT license */

/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
Binary file added dist/ef0ca63316357c3c262f.module.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion dist/node.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "web3-cardano-token",
"version": "0.0.12",
"version": "0.1.17",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would stick with version 0.1.0 here perhaps. If the API has no breaking changes then I would just increase it to 0.0.13.

"private": false,
"description": "Web3 Token is a new way to authenticate users in hybrid dApps using signed messages.",
"author": "pyropy",
"scripts": {
"build": "webpack --mode=production --progress"
},
"types": "src/lib.d.ts",
"module": "src/lib.js",
"main": "dist/web3-cardano-token.js",
"dependencies": {
Expand Down
25 changes: 25 additions & 0 deletions src/browser.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type COSESign1 = {
signature: string;
key: string;
}

type Signer = (msg: string) => PromiseLike<COSESign1>;

export function sign(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we stick with arrow function types? Also we should make first letter of the function uppercase ⏫

signer: Signer,
expires_in?: string | number,
body?: Object
): PromiseLike<string>;

export function verify(token: string): {
address: string;
body: Object;
};

declare const Web3Token: {
sign: typeof sign;
verify: typeof verify;
};

export default Web3Token;

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Types ❤️

32 changes: 18 additions & 14 deletions src/lib.d.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
type Signer = (msg: string) => PromiseLike<string>
type COSESign1 = {
signature: string;
key: string;
}

type Signer = (msg: string) => PromiseLike<COSESign1>;

export function sign(
signer: Signer,
expires_in?: string | number,
body?: Object): PromiseLike<string>
signer: Signer,
expires_in?: string | number,
body?: Object
): PromiseLike<string>;

export function verify(
token: string
): {
address: string,
body: Object
}
export function verify(token: string): {
address: string;
body: Object;
};

declare const Web3Token: {
sign: typeof sign,
verify: typeof verify
}
sign: typeof sign;
verify: typeof verify;
};

export default Web3Token
export default Web3Token;
9 changes: 4 additions & 5 deletions src/lib/sign.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,20 @@ export const sign = async (signer, expires_in = '1d', body = {}) => {
const msg = buildMessage(data);

if(typeof signer === 'function') {
var signature = await signer(msg);
var COSESign1Message = await signer(msg);
} else {
throw new Error('"signer" argument should be a function that returns a signature eg: "msg => web3.eth.personal.sign(msg, <YOUR_ADDRESS>)"')
}

if (typeof(signature) === "object") {
signature = signature.signature
}
const {signature, key} = COSESign1Message;

if(typeof signature !== 'string') {
throw new Error('"signer" argument should be a function that returns a signature string (Promise<string>)')
throw new Error('"signature" argument should be a function that returns a signature string (Promise<string>)')
}

const token = Base64.encode(JSON.stringify({
signature,
key,
body: msg,
}))

Expand Down
107 changes: 103 additions & 4 deletions src/lib/verify.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import Base64 from "base-64";
import parseAsHeaders from "parse-headers";
import { Buffer } from "buffer";
import Loader from "./loader";
import Loader from "./loader.js";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is .js needed for import?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No its not needed


const DEBUG = !!process.env.DEBUG_WEB3;

/**
*
* @param {string} token Signed Web3 Token
* @returns {boolean}
*/
export const verify = async (token) => {
if (!token || !token.length) {
throw new Error("Token required.");
Expand All @@ -19,7 +26,7 @@ export const verify = async (token) => {
}

try {
var { body, signature } = JSON.parse(base64_decoded);
var { body, signature, key } = JSON.parse(base64_decoded);
} catch (error) {
throw new Error("Token malformed (unparsable JSON)");
}
Expand All @@ -38,12 +45,47 @@ export const verify = async (token) => {
Buffer.from(Buffer.from(signature, "hex"), "hex")
);

log('message', message);

const headermap = message.headers().protected().deserialized_headers();

const address = Loader.Cardano.Address.from_bytes(
headermap.header(Loader.Message.Label.new_text("address")).as_bytes()
);
const parsed_body = parseAsHeaders(body);

const coseKey = Loader.Message.COSEKey.from_bytes(Buffer.from(key, "hex"));

const publicKey = Loader.Cardano.PublicKey.from_bytes(
coseKey
.header(
Loader.Message.Label.new_int(
Loader.Message.Int.new_negative(Loader.Message.BigNum.from_str("2"))
)
)
.as_bytes()
);

log('publicKey', Buffer.from(publicKey.as_bytes()).toString('hex'));
const verifyAddressResponse = verifyAddress(address, publicKey);

if (!verifyAddressResponse.status) {
throw new Error(
`Address verification failed: (${verifyAddressResponse.message} (${verifyAddressResponse.code}))`
);
}

const data = message.signed_data().to_bytes();
const body_from_token = Buffer.from(data).toString("utf-8");

const ed25519Sig = Loader.Cardano.Ed25519Signature.from_bytes(message.signature())

if (!publicKey.verify(data, ed25519Sig)) {
throw new Error(
`Message integrity check failed (has the message been tampered with?)`
);
}

const parsed_body = parseAsHeaders(body_from_token);

if (
parsed_body["expire-date"] &&
Expand All @@ -52,5 +94,62 @@ export const verify = async (token) => {
throw new Error("Token expired");
}

return { address: address.to_bech32(), body: parsed_body };
return {
address: address.to_bech32(),
network: address.network_id(),
body: parsed_body,
};
};

/**

* Validate the Address provided. To do this we take the Address (or Base Address)
* and compare it to an address (BaseAddress or RewardAddress) reconstructed from the
* publicKey.
* @param {Loader.Cardano.Address} checkAddress
* @param {Loader.Cardano.PublicKey} publicKey
* @returns {{status: bool, msg?: string, code?: number}}
*/
const verifyAddress = (checkAddress, publicKey) => {
log('In verifyAddress', checkAddress, publicKey);
let errorMsg = "";
try {
//reconstruct address
log('Step verifyAddress', 1);
const paymentKeyHash = publicKey.hash();

log('Step verifyAddress', 2);
const baseAddress = Loader.Cardano.BaseAddress.from_address(checkAddress);
const stakeKeyHash = baseAddress.stake_cred().to_keyhash();
log('Step verifyAddress', 3);
const reconstructedAddress = Loader.Cardano.BaseAddress.new(
checkAddress.network_id(),
Loader.Cardano.StakeCredential.from_keyhash(paymentKeyHash),
Loader.Cardano.StakeCredential.from_keyhash(stakeKeyHash)
);
log('Step verifyAddress', 4);

const status = checkAddress.to_bech32() === reconstructedAddress.to_address().to_bech32();
log('Step verifyAddress', 5, status);
return {
status,
msg: status ? "Valid Address" : "Base Address does not validate to Reconstructed address",
code: 1
};
} catch (e) {
log('Err verifyAddress', e);
errorMsg += ` ${e.message}`
}

return {
status: false,
msg: `Error: ${errorMsg}`,
code: 3
};
};



function log(message, ...optionalParams) {
DEBUG && console.log(message, optionalParams);
}
30 changes: 30 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Loader from "./src/lib/loader.js";
import Base64 from "base-64";

import { verify } from "./src/lib/verify.js";


const signedToken =
"eyJzaWduYXR1cmUiOiI4NDU4NDZhMjAxMjc2NzYxNjQ2NDcyNjU3MzczNTgzOTAwZDAwNmViNzc4M2U4YzkzMTYwYjJiYWIyODdiYzhhNmYwNjllOWU2OTBjZDgyYmMwYjUyYThjMzE3MzBkODA1YjZhMmNmNjc5OThmMGZjZDA3MGNlMGI2ZTg1OTU3ZmQ3NThjZjBhZTM0OGQyNjVlYmExNjY2ODYxNzM2ODY1NjRmNDU4NDA1NzY1NjIzMzJkNTQ2ZjZiNjU2ZTJkNTY2NTcyNzM2OTZmNmUzYTIwMzEwYTQ1Nzg3MDY5NzI2NTJkNDQ2MTc0NjUzYTIwNTc2NTY0MmMyMDMyMzMyMDQ2NjU2MjIwMzIzMDMyMzIyMDMwMzkzYTMzMzkzYTMzMzMyMDQ3NGQ1NDU4NDBhYWU2OWIxMDIzYTJhZGUzZGZjMzI2ZGMxMTJjNGNjM2Q4Zjc2Njc3NDU3YmQzZGZlNzc5MzA1OTljODY4NTc2ODNiYjFjYWI3OWU5YjIwZjVlZTJkMmVmYTI4ODNjNGVlZTFlNjFjNTc2OTZkY2M1ZTMyOWY0NmE3MWVlMjEwYiIsImtleSI6ImE0MDEwMTAzMjcyMDA2MjE1ODIwZGM2YzIxY2I5ZjVmOTZjN2I5OTMyMjM3Nzc4ZTA1M2RjMjczYTE0ODRlYzA1Nzc1OTQ2YTQzOTczOWNlYjBlYSIsImJvZHkiOiJXZWIzLVRva2VuLVZlcnNpb246IDFcbkV4cGlyZS1EYXRlOiBXZWQsIDIzIEZlYiAyMDIyIDA5OjM5OjMzIEdNVCJ9";

// const signedToken_changed =
// "ewoJImRhdGEiOiAid2hvIGNhcmVzIiwKCSJzaWduYXR1cmUiOiAiODQ1ODY5YTMwMTI3MDQ1ODIwNmY5Mzg5ZTQ1MzRlMWY1MjM0NjMwYWE0YmE5ZDg2ZDU0NDJlZWI0MzZkNzA2Njg5MmYwNjhlYmU2MmJkMDZiZjY3NjE2NDY0NzI2NTczNzM1ODM5MDA4OTQwMDAyM2UyMmVjZWEyY2ExMjI4M2JjNGM2NWI3ODcyMzkwNWJlMzMwNmQxNzE2ZTAzOTFmZDZjN2JiZjkzYzIyMDBkYTExMjYzMzRmY2RkNDY5OWM2YTEyN2Y4ZWZjMzJjOTk5NDQwYWE1YTc1YTE2NjY4NjE3MzY4NjU2NGY0NTg0MDU3NjU2MjMzMmQ1NDZmNmI2NTZlMmQ1NjY1NzI3MzY5NmY2ZTNhMjAzMTBhNDU3ODcwNjk3MjY1MmQ0NDYxNzQ2NTNhMjA1Mzc1NmUyYzIwMzAzODIwNDQ2NTYzMjAzMjMwMzIzMTIwMzAzNTNhMzIzNDNhMzAzMzIwNDc0ZDU0NTg0MDgxYjA2MGVhMDUxZjM0YTJiNWU2MjZkMTM2ODAzNDA5YTcwMGQwY2Y0ODQyNTdkMTZjYzNmNjBhNmViZTQ2NGFhNzFlOGZkZjg5YmQwZTc5MDQ5MGE5NWIwNGE4ODNiMTA0ZjEwN2E3OTcyNzJhNzYwYzk0NzY5ZmE5OTUyODAwIgp9Cgo=";

(async () => {



// console.log(data)

try {
console.log(await verify(signedToken));
} catch (error) {
console.log(error);
}

// try {
// console.log(await verify(signedToken_changed));
// } catch (err) {
// console.log(err);
// }
})();
Loading