rehaul auth system

This commit is contained in:
Ryan Shea
2017-03-04 11:16:40 -05:00
parent 96fbacec71
commit 8c81f4d67c
26 changed files with 347 additions and 1024 deletions

2
.gitignore vendored
View File

@@ -32,6 +32,6 @@ unused
# Folder to ignore for development with es6
lib
docs/tokenfiles/*.json
docs/token-files/*.json
src/testing/browser/blockstack-proofs.js

View File

@@ -1,37 +0,0 @@
[
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiI2ZDJmYzM1My0yNDE5LTQ0MjktYmVmMi03NDAzNTNmYTA1MjUiLCJpYXQiOiIyMDE3LTAyLTI2VDIwOjE3OjI4LjUwNloiLCJleHAiOiIyMDE4LTAyLTI2VDIwOjE3OjI4LjUwNloiLCJzdWJqZWN0Ijp7InB1YmxpY0tleSI6IjAzODVmMzNmYTk0MjVhOTQwZjg1YmE0NjNmN2I2ZjIyYjE1NjcxNjNkMmZlNjAzNGNlMDkzY2NiOGUyOTgwZWRhYSJ9LCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDM4NWYzM2ZhOTQyNWE5NDBmODViYTQ2M2Y3YjZmMjJiMTU2NzE2M2QyZmU2MDM0Y2UwOTNjY2I4ZTI5ODBlZGFhIn0sImNsYWltIjp7IkBjb250ZXh0IjoiaHR0cDovL3NjaGVtYS5vcmcvIiwiQHR5cGUiOiJDcmVhdGl2ZVdvcmsiLCJuYW1lIjoiQmFsbG9vbiBEb2ciLCJjcmVhdG9yIjpbeyJAdHlwZSI6IlBlcnNvbiIsIkBpZCI6InRoZXJlYWxqZWZma29vbnMuaWQiLCJuYW1lIjoiSmVmZiBLb29ucyJ9XSwiZGF0ZUNyZWF0ZWQiOiIxOTk0LTA1LTA5VDAwOjAwOjAwLTA0MDAiLCJkYXRlUHVibGlzaGVkIjoiMjAxNS0xMi0xMFQxNDo0NDoyNi0wNTAwIn19.vfd6vt3ARA38UJMN34EtF0Nl6buH9HMfYpHgpzVxWhIcO1dKpM4nSQvZTGKcUki0k7vh9CHpjv33K53rjes8gA",
"decodedToken": {
"header": {
"typ": "JWT",
"alg": "ES256K"
},
"payload": {
"jti": "6d2fc353-2419-4429-bef2-740353fa0525",
"iat": "2017-02-26T20:17:28.506Z",
"exp": "2018-02-26T20:17:28.506Z",
"subject": {
"publicKey": "0385f33fa9425a940f85ba463f7b6f22b1567163d2fe6034ce093ccb8e2980edaa"
},
"issuer": {
"publicKey": "0385f33fa9425a940f85ba463f7b6f22b1567163d2fe6034ce093ccb8e2980edaa"
},
"claim": {
"@context": "http://schema.org/",
"@type": "CreativeWork",
"name": "Balloon Dog",
"creator": [
{
"@type": "Person",
"@id": "therealjeffkoons.id",
"name": "Jeff Koons"
}
],
"dateCreated": "1994-05-09T00:00:00-0400",
"datePublished": "2015-12-10T14:44:26-0500"
}
},
"signature": "vfd6vt3ARA38UJMN34EtF0Nl6buH9HMfYpHgpzVxWhIcO1dKpM4nSQvZTGKcUki0k7vh9CHpjv33K53rjes8gA"
}
}
]

View File

@@ -1,60 +0,0 @@
[
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiJjZjY2MmNkNi0xNDI1LTQ3YzktOWE1ZS1kMWFlYzExNTQwNzAiLCJpYXQiOiIyMDE3LTAyLTI2VDIwOjE3OjI4LjQzOFoiLCJleHAiOiIyMDE4LTAyLTI2VDIwOjE3OjI4LjQzOFoiLCJzdWJqZWN0Ijp7InB1YmxpY0tleSI6IjAzZmQyYzkxMTM1NjAxNTg1YTUxMGMzMTE0Zjg5OTk2NTQxMDcwNWEwNDc0NjU3MjEwOTdiYTU4NTg2ZTQ5NDEzNiJ9LCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDNmZDJjOTExMzU2MDE1ODVhNTEwYzMxMTRmODk5OTY1NDEwNzA1YTA0NzQ2NTcyMTA5N2JhNTg1ODZlNDk0MTM2In0sImNsYWltIjp7IkBjb250ZXh0IjoiaHR0cDovL3NjaGVtYS5vcmcvIiwiQHR5cGUiOiJPcmdhbml6YXRpb24iLCJuYW1lIjoiR29vZ2xlIiwibGVnYWxOYW1lIjoiR29vZ2xlIEluYy4iLCJlbWFpbCI6ImhlbGxvQGdvb2dsZS5vcmciLCJhZGRyZXNzIjp7IkB0eXBlIjoiUG9zdGFsQWRkcmVzcyIsImFkZHJlc3NMb2NhbGl0eSI6Ik1vdW50YWluIFZpZXcsIENBIiwicG9zdGFsQ29kZSI6Ijk0MDQzIiwic3RyZWV0QWRkcmVzcyI6IjE2MDAgQW1waGl0aGVhdHJlIFBhcmt3YXkifSwiZW1wbG95ZWUiOlt7IkB0eXBlIjoiUGVyc29uIiwiQGlkIjoibGFycnlwYWdlLmlkIiwibmFtZSI6IkxhcnJ5IFBhZ2UifSx7IkB0eXBlIjoiUGVyc29uIiwiQGlkIjoic2VyZ2V5YnJpbi5pZCIsIm5hbWUiOiJTZXJnZXkgQnJpbiJ9XSwiaW1hZ2UiOlt7IkB0eXBlIjoiSW1hZ2VPYmplY3QiLCJuYW1lIjoibG9nbyIsImNvbnRlbnRVcmwiOiJodHRwczovL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzJ4L2dvb2dsZWxvZ29fY29sb3JfMjcyeDkyZHAucG5nIn1dLCJwYXJlbnRPcmdhbml6YXRpb24iOnsiQHR5cGUiOiJPcmdhbml6YXRpb24iLCJAaWQiOiJhbHBoYWJldC5pZCIsIm5hbWUiOiJBbHBoYWJldCBJbmMuIn19fQ.hrF-bxIIAQ3zw2KjddH88cjv_ao0ua5XQPddBrCnT5xnwwQ0lvsrAM3uRq9ib98Bldd0N6YBBzL668g2Ao09Fw",
"decodedToken": {
"header": {
"typ": "JWT",
"alg": "ES256K"
},
"payload": {
"jti": "cf662cd6-1425-47c9-9a5e-d1aec1154070",
"iat": "2017-02-26T20:17:28.438Z",
"exp": "2018-02-26T20:17:28.438Z",
"subject": {
"publicKey": "03fd2c91135601585a510c3114f899965410705a047465721097ba58586e494136"
},
"issuer": {
"publicKey": "03fd2c91135601585a510c3114f899965410705a047465721097ba58586e494136"
},
"claim": {
"@context": "http://schema.org/",
"@type": "Organization",
"name": "Google",
"legalName": "Google Inc.",
"email": "hello@google.org",
"address": {
"@type": "PostalAddress",
"addressLocality": "Mountain View, CA",
"postalCode": "94043",
"streetAddress": "1600 Amphitheatre Parkway"
},
"employee": [
{
"@type": "Person",
"@id": "larrypage.id",
"name": "Larry Page"
},
{
"@type": "Person",
"@id": "sergeybrin.id",
"name": "Sergey Brin"
}
],
"image": [
{
"@type": "ImageObject",
"name": "logo",
"contentUrl": "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"
}
],
"parentOrganization": {
"@type": "Organization",
"@id": "alphabet.id",
"name": "Alphabet Inc."
}
}
},
"signature": "hrF-bxIIAQ3zw2KjddH88cjv_ao0ua5XQPddBrCnT5xnwwQ0lvsrAM3uRq9ib98Bldd0N6YBBzL668g2Ao09Fw"
}
}
]

View File

@@ -1,106 +0,0 @@
[
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiIyNThkMTI4NS0yZDhjLTRhOTEtYjQ2OC0zMDRjODVkYTUxYzgiLCJpYXQiOiIyMDE3LTAyLTI2VDIwOjE3OjI4LjU5NFoiLCJleHAiOiIyMDE4LTAyLTI2VDIwOjE3OjI4LjU5NFoiLCJzdWJqZWN0Ijp7InB1YmxpY0tleSI6IjAyZDY2Y2UwOWI4ZWNkZTYyYjQ2NzcxMTEyMTYyZGY5YzlmNzU3MDJmYjdlZTU0NmZkMjYxZGQxYmZjZTU2NTk2MyJ9LCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDJkNjZjZTA5YjhlY2RlNjJiNDY3NzExMTIxNjJkZjljOWY3NTcwMmZiN2VlNTQ2ZmQyNjFkZDFiZmNlNTY1OTYzIn0sImNsYWltIjp7IkB0eXBlIjoiUGVyc29uIiwiQGNvbnRleHQiOiJodHRwOi8vc2NoZW1hLm9yZy8iLCJuYW1lIjoiTmF2YWwgUmF2aWthbnQiLCJnaXZlbk5hbWUiOiJOYXZhbCIsImZhbWlseU5hbWUiOiJSYXZpa2FudCIsImRlc2NyaXB0aW9uIjoiQ28tZm91bmRlciBvZiBBbmdlbExpc3QiLCJpbWFnZSI6W3siQHR5cGUiOiJJbWFnZU9iamVjdCIsIm5hbWUiOiJhdmF0YXIiLCJjb250ZW50VXJsIjoiaHR0cHM6Ly9wYnMudHdpbWcuY29tL3Byb2ZpbGVfaW1hZ2VzLzM2OTY2MTczMjgvNjY3ODc0YzU5MzY3NjRkOTNkNTZjY2M3NmEyYmNjMTMuanBlZyJ9LHsiQHR5cGUiOiJJbWFnZU9iamVjdCIsIm5hbWUiOiJiYWNrZ3JvdW5kIiwiY29udGVudFVybCI6Imh0dHBzOi8vcGJzLnR3aW1nLmNvbS9wcm9maWxlX2Jhbm5lcnMvNzQ1MjczLzEzNTU3MDU3Nzcvd2ViX3JldGluYSJ9XSwid2Vic2l0ZSI6W3siQHR5cGUiOiJXZWJTaXRlIiwidXJsIjoiYW5nZWwuY28ifV0sImFjY291bnQiOlt7IkB0eXBlIjoiQWNjb3VudCIsInNlcnZpY2UiOiJmYWNlYm9vayIsImlkZW50aWZpZXIiOiJuYXZhbHIiLCJwcm9vZlR5cGUiOiJodHRwIiwicHJvb2ZVcmwiOiJodHRwczovL2ZhY2Vib29rLmNvbS9uYXZhbHIvcG9zdHMvMTAxNTIxOTA3MzQwNzcyNjEifSx7IkB0eXBlIjoiQWNjb3VudCIsInNlcnZpY2UiOiJ0d2l0dGVyIiwiaWRlbnRpZmllciI6Im5hdmFsIiwicHJvb2ZUeXBlIjoiaHR0cCIsInByb29mVXJsIjoiaHR0cHM6Ly90d2l0dGVyLmNvbS9uYXZhbC9zdGF0dXMvNDg2NjA5MjY2MjEyNDk5NDU2In0seyJAdHlwZSI6IkFjY291bnQiLCJzZXJ2aWNlIjoiZ2l0aHViIiwiaWRlbnRpZmllciI6Im5hdmFsciIsInByb29mVHlwZSI6Imh0dHAiLCJwcm9vZlVybCI6Imh0dHBzOi8vZ2lzdC5naXRodWIuY29tL25hdmFsci9mMzFhNzQwNTRmODU5ZWMwYWM2YSJ9LHsiQHR5cGUiOiJBY2NvdW50Iiwic2VydmljZSI6ImJpdGNvaW4iLCJyb2xlIjoicGF5bWVudCIsImlkZW50aWZpZXIiOiIxOTE5VXJoWXloczQ3MXBzOENGY0ozRFJwV1NkYThxdFNrIiwicHJvb2ZUeXBlIjoic2lnbmF0dXJlIiwicHJvb2ZNZXNzYWdlIjoiVmVyaWZ5aW5nIHRoYXQgK25hdmFsIGlzIG15IGJsb2NrY2hhaW4gSUQuIiwicHJvb2ZTaWduYXR1cmUiOiJJQ3VSQStEcTVEbjhBaVk5UCttY0x6R3lpYlBnRzBlYzlDcGh0TWs1MTJ1UGRCNWVBbmNEU0hoUVpZLzdreWN2bDZQTEZFdVIrajNPTS9LMlZleTErRVU9In1dLCJ3b3Jrc0ZvciI6W3siQHR5cGUiOiJPcmdhbml6YXRpb24iLCJAaWQiOiJhbmdlbGxpc3QuaWQifV0sImtub3dzIjpbeyJAdHlwZSI6IlBlcnNvbiIsIkBpZCI6Im11bmVlYi5pZCJ9LHsiQHR5cGUiOiJQZXJzb24iLCJAaWQiOiJyeWFuLmlkIn1dLCJiaXJ0aERhdGUiOiIxOTczLTAxLTAxIiwidGF4SUQiOiIwMDAtMDAtMDAwMCIsImFkZHJlc3MiOnsiQHR5cGUiOiJQb3N0YWxBZGRyZXNzIiwic3RyZWV0QWRkcmVzcyI6IjE2IE1haWRlbiBMbiIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28sIENBIiwicG9zdGFsQ29kZSI6Ijk0MTA4IiwiYWRkcmVzc0NvdW50cnkiOiJVbml0ZWQgU3RhdGVzIn19fQ.YLlbAJW9dWKMxTQcNFa1wOWgrOTUjJbCMlVnMd2teNa1GHZsC_CdwKzOHl_QZkCdBJ3MT0slgxr2OE6m6PlC_w",
"decodedToken": {
"header": {
"typ": "JWT",
"alg": "ES256K"
},
"payload": {
"jti": "258d1285-2d8c-4a91-b468-304c85da51c8",
"iat": "2017-02-26T20:17:28.594Z",
"exp": "2018-02-26T20:17:28.594Z",
"subject": {
"publicKey": "02d66ce09b8ecde62b46771112162df9c9f75702fb7ee546fd261dd1bfce565963"
},
"issuer": {
"publicKey": "02d66ce09b8ecde62b46771112162df9c9f75702fb7ee546fd261dd1bfce565963"
},
"claim": {
"@type": "Person",
"@context": "http://schema.org/",
"name": "Naval Ravikant",
"givenName": "Naval",
"familyName": "Ravikant",
"description": "Co-founder of AngelList",
"image": [
{
"@type": "ImageObject",
"name": "avatar",
"contentUrl": "https://pbs.twimg.com/profile_images/3696617328/667874c5936764d93d56ccc76a2bcc13.jpeg"
},
{
"@type": "ImageObject",
"name": "background",
"contentUrl": "https://pbs.twimg.com/profile_banners/745273/1355705777/web_retina"
}
],
"website": [
{
"@type": "WebSite",
"url": "angel.co"
}
],
"account": [
{
"@type": "Account",
"service": "facebook",
"identifier": "navalr",
"proofType": "http",
"proofUrl": "https://facebook.com/navalr/posts/10152190734077261"
},
{
"@type": "Account",
"service": "twitter",
"identifier": "naval",
"proofType": "http",
"proofUrl": "https://twitter.com/naval/status/486609266212499456"
},
{
"@type": "Account",
"service": "github",
"identifier": "navalr",
"proofType": "http",
"proofUrl": "https://gist.github.com/navalr/f31a74054f859ec0ac6a"
},
{
"@type": "Account",
"service": "bitcoin",
"role": "payment",
"identifier": "1919UrhYyhs471ps8CFcJ3DRpWSda8qtSk",
"proofType": "signature",
"proofMessage": "Verifying that +naval is my blockchain ID.",
"proofSignature": "ICuRA+Dq5Dn8AiY9P+mcLzGyibPgG0ec9CphtMk512uPdB5eAncDSHhQZY/7kycvl6PLFEuR+j3OM/K2Vey1+EU="
}
],
"worksFor": [
{
"@type": "Organization",
"@id": "angellist.id"
}
],
"knows": [
{
"@type": "Person",
"@id": "muneeb.id"
},
{
"@type": "Person",
"@id": "ryan.id"
}
],
"birthDate": "1973-01-01",
"taxID": "000-00-0000",
"address": {
"@type": "PostalAddress",
"streetAddress": "16 Maiden Ln",
"addressLocality": "San Francisco, CA",
"postalCode": "94108",
"addressCountry": "United States"
}
}
},
"signature": "YLlbAJW9dWKMxTQcNFa1wOWgrOTUjJbCMlVnMd2teNa1GHZsC_CdwKzOHl_QZkCdBJ3MT0slgxr2OE6m6PlC_w"
}
}
]

View File

@@ -1,106 +0,0 @@
[
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiJmMjY2NzI2MS1jOTZlLTRjOGQtYmIwNy0xMTI2MzdmYWY5M2QiLCJpYXQiOiIyMDE3LTAyLTI2VDIwOjE3OjI4LjM2OVoiLCJleHAiOiIyMDE4LTAyLTI2VDIwOjE3OjI4LjM2OVoiLCJzdWJqZWN0Ijp7InB1YmxpY0tleSI6IjAzZDRiNzIzNWQ4OWYxNmM0ZmY3NGFmYzRhOGY2ZTI1ZmFkNjI1ZjY3MWQxNDk0YjI4NDc0YTM0ZDFmZWI2NmYzMyJ9LCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDNkNGI3MjM1ZDg5ZjE2YzRmZjc0YWZjNGE4ZjZlMjVmYWQ2MjVmNjcxZDE0OTRiMjg0NzRhMzRkMWZlYjY2ZjMzIn0sImNsYWltIjp7IkBjb250ZXh0IjoiaHR0cDovL3NjaGVtYS5vcmcvIiwiQHR5cGUiOiJQZXJzb24iLCJuYW1lIjoiTmF2YWwgUmF2aWthbnQiLCJnaXZlbk5hbWUiOiJOYXZhbCIsImZhbWlseU5hbWUiOiJSYXZpa2FudCIsImRlc2NyaXB0aW9uIjoiQ28tZm91bmRlciBvZiBBbmdlbExpc3QiLCJpbWFnZSI6W3siQHR5cGUiOiJJbWFnZU9iamVjdCIsIm5hbWUiOiJhdmF0YXIiLCJjb250ZW50VXJsIjoiaHR0cHM6Ly9wYnMudHdpbWcuY29tL3Byb2ZpbGVfaW1hZ2VzLzM2OTY2MTczMjgvNjY3ODc0YzU5MzY3NjRkOTNkNTZjY2M3NmEyYmNjMTMuanBlZyJ9LHsiQHR5cGUiOiJJbWFnZU9iamVjdCIsIm5hbWUiOiJiYWNrZ3JvdW5kIiwiY29udGVudFVybCI6Imh0dHBzOi8vcGJzLnR3aW1nLmNvbS9wcm9maWxlX2Jhbm5lcnMvNzQ1MjczLzEzNTU3MDU3Nzcvd2ViX3JldGluYSJ9XSwid2Vic2l0ZSI6W3siQHR5cGUiOiJXZWJTaXRlIiwidXJsIjoiYW5nZWwuY28ifV0sImFjY291bnQiOlt7IkB0eXBlIjoiQWNjb3VudCIsInNlcnZpY2UiOiJmYWNlYm9vayIsImlkZW50aWZpZXIiOiJuYXZhbHIiLCJwcm9vZlR5cGUiOiJodHRwIiwicHJvb2ZVcmwiOiJodHRwczovL2ZhY2Vib29rLmNvbS9uYXZhbHIvcG9zdHMvMTAxNTIxOTA3MzQwNzcyNjEifSx7IkB0eXBlIjoiQWNjb3VudCIsInNlcnZpY2UiOiJ0d2l0dGVyIiwiaWRlbnRpZmllciI6Im5hdmFsIiwicHJvb2ZUeXBlIjoiaHR0cCIsInByb29mVXJsIjoiaHR0cHM6Ly90d2l0dGVyLmNvbS9uYXZhbC9zdGF0dXMvNDg2NjA5MjY2MjEyNDk5NDU2In0seyJAdHlwZSI6IkFjY291bnQiLCJzZXJ2aWNlIjoiZ2l0aHViIiwiaWRlbnRpZmllciI6Im5hdmFsciIsInByb29mVHlwZSI6Imh0dHAiLCJwcm9vZlVybCI6Imh0dHBzOi8vZ2lzdC5naXRodWIuY29tL25hdmFsci9mMzFhNzQwNTRmODU5ZWMwYWM2YSJ9LHsiQHR5cGUiOiJBY2NvdW50Iiwic2VydmljZSI6ImJpdGNvaW4iLCJyb2xlIjoicGF5bWVudCIsImlkZW50aWZpZXIiOiIxOTE5VXJoWXloczQ3MXBzOENGY0ozRFJwV1NkYThxdFNrIiwicHJvb2ZUeXBlIjoic2lnbmF0dXJlIiwicHJvb2ZNZXNzYWdlIjoiVmVyaWZ5aW5nIHRoYXQgK25hdmFsIGlzIG15IGJsb2NrY2hhaW4gSUQuIiwicHJvb2ZTaWduYXR1cmUiOiJJQ3VSQStEcTVEbjhBaVk5UCttY0x6R3lpYlBnRzBlYzlDcGh0TWs1MTJ1UGRCNWVBbmNEU0hoUVpZLzdreWN2bDZQTEZFdVIrajNPTS9LMlZleTErRVU9In1dLCJ3b3Jrc0ZvciI6W3siQHR5cGUiOiJPcmdhbml6YXRpb24iLCJAaWQiOiJhbmdlbGxpc3QuaWQifV0sImtub3dzIjpbeyJAdHlwZSI6IlBlcnNvbiIsIkBpZCI6Im11bmVlYi5pZCJ9LHsiQHR5cGUiOiJQZXJzb24iLCJAaWQiOiJyeWFuLmlkIn1dLCJiaXJ0aERhdGUiOiIxOTczLTAxLTAxIiwidGF4SUQiOiIwMDAtMDAtMDAwMCIsImFkZHJlc3MiOnsiQHR5cGUiOiJQb3N0YWxBZGRyZXNzIiwic3RyZWV0QWRkcmVzcyI6IjE2IE1haWRlbiBMbiIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28sIENBIiwicG9zdGFsQ29kZSI6Ijk0MTA4IiwiYWRkcmVzc0NvdW50cnkiOiJVbml0ZWQgU3RhdGVzIn19fQ.yVrQR9sNuyjHcknnbBa5BwILYc4caT8fod6BO6nTnn_cfk8qRINHd4FkV4WC2GssE52OtRElM3DByR5BQi7bbQ",
"decodedToken": {
"header": {
"typ": "JWT",
"alg": "ES256K"
},
"payload": {
"jti": "f2667261-c96e-4c8d-bb07-112637faf93d",
"iat": "2017-02-26T20:17:28.369Z",
"exp": "2018-02-26T20:17:28.369Z",
"subject": {
"publicKey": "03d4b7235d89f16c4ff74afc4a8f6e25fad625f671d1494b28474a34d1feb66f33"
},
"issuer": {
"publicKey": "03d4b7235d89f16c4ff74afc4a8f6e25fad625f671d1494b28474a34d1feb66f33"
},
"claim": {
"@context": "http://schema.org/",
"@type": "Person",
"name": "Naval Ravikant",
"givenName": "Naval",
"familyName": "Ravikant",
"description": "Co-founder of AngelList",
"image": [
{
"@type": "ImageObject",
"name": "avatar",
"contentUrl": "https://pbs.twimg.com/profile_images/3696617328/667874c5936764d93d56ccc76a2bcc13.jpeg"
},
{
"@type": "ImageObject",
"name": "background",
"contentUrl": "https://pbs.twimg.com/profile_banners/745273/1355705777/web_retina"
}
],
"website": [
{
"@type": "WebSite",
"url": "angel.co"
}
],
"account": [
{
"@type": "Account",
"service": "facebook",
"identifier": "navalr",
"proofType": "http",
"proofUrl": "https://facebook.com/navalr/posts/10152190734077261"
},
{
"@type": "Account",
"service": "twitter",
"identifier": "naval",
"proofType": "http",
"proofUrl": "https://twitter.com/naval/status/486609266212499456"
},
{
"@type": "Account",
"service": "github",
"identifier": "navalr",
"proofType": "http",
"proofUrl": "https://gist.github.com/navalr/f31a74054f859ec0ac6a"
},
{
"@type": "Account",
"service": "bitcoin",
"role": "payment",
"identifier": "1919UrhYyhs471ps8CFcJ3DRpWSda8qtSk",
"proofType": "signature",
"proofMessage": "Verifying that +naval is my blockchain ID.",
"proofSignature": "ICuRA+Dq5Dn8AiY9P+mcLzGyibPgG0ec9CphtMk512uPdB5eAncDSHhQZY/7kycvl6PLFEuR+j3OM/K2Vey1+EU="
}
],
"worksFor": [
{
"@type": "Organization",
"@id": "angellist.id"
}
],
"knows": [
{
"@type": "Person",
"@id": "muneeb.id"
},
{
"@type": "Person",
"@id": "ryan.id"
}
],
"birthDate": "1973-01-01",
"taxID": "000-00-0000",
"address": {
"@type": "PostalAddress",
"streetAddress": "16 Maiden Ln",
"addressLocality": "San Francisco, CA",
"postalCode": "94108",
"addressCountry": "United States"
}
}
},
"signature": "yVrQR9sNuyjHcknnbBa5BwILYc4caT8fod6BO6nTnn_cfk8qRINHd4FkV4WC2GssE52OtRElM3DByR5BQi7bbQ"
}
}
]

View File

@@ -1,93 +0,0 @@
[
{
"decodedToken": {
"header": {
"alg": "ES256K",
"typ": "JWT"
},
"payload": {
"issuedAt": "2016-12-21T02:20:24.575047",
"claim": {
"image": [
{
"contentUrl": "https://s3.amazonaws.com/kd4/ryan",
"name": "avatar",
"@type": "ImageObject"
},
{
"contentUrl": "https://s3.amazonaws.com/dx3/ryan",
"name": "cover",
"@type": "ImageObject"
}
],
"@type": "Person",
"website": [
{
"url": "http://shea.io",
"@type": "WebSite"
}
],
"description": "Co-founder of Blockstack Inc.",
"address": {
"addressLocality": "New York",
"@type": "PostalAddress"
},
"account": [
{
"identifier": "1LFS37yRSibwbf8CnXeCn5t1GKeTEZMmu9",
"role": "payment",
"@type": "Account",
"service": "bitcoin"
},
{
"contentUrl": "https://s3.amazonaws.com/pk9/ryan",
"identifier": "1E4329E6634C75730D4D88C0638F2769D55B9837",
"@type": "Account",
"service": "pgp"
},
{
"identifier": "f2250123a6af138c86b30f3233b338961dc8fbc3",
"proofType": "http",
"proofUrl": "https://www.facebook.com/msrobot0/posts/10153644446452759",
"service": "openbazaar",
"@type": "Account"
},
{
"identifier": "ryaneshea",
"proofType": "http",
"proofUrl": "https://twitter.com/ryaneshea/status/765575388735082496",
"service": "twitter",
"@type": "Account"
},
{
"identifier": "shea256",
"proofType": "http",
"proofUrl": "https://gist.github.com/shea256/a6dc1f3182f28bb2285feaef07a14340",
"service": "github",
"@type": "Account"
},
{
"identifier": "ryaneshea",
"proofType": "http",
"proofUrl": "https://www.facebook.com/ryaneshea/posts/10154182997407713",
"service": "facebook",
"@type": "Account"
}
],
"name": "Ryan Shea"
},
"expiresAt": "2017-12-21T02:20:24.575047",
"subject": {
"publicKey": "0312ccf3255cb005e42c186aa3d2302083b306a52c1f0cb47b1119639f134e6695"
},
"issuer": {
"publicKey": "0312ccf3255cb005e42c186aa3d2302083b306a52c1f0cb47b1119639f134e6695"
}
},
"signature": "YVoNsoJCTMcXIwqa9D5kinkUrnyppsYus7Z-8cn7o9hA6_IG9zkoZGSvsIzfqqjG1mV8JNV1Nh04CZl1qrt1YQ"
},
"token": "eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJpc3N1ZWRBdCI6IjIwMTYtMTItMjFUMDI6MjA6MjQuNTc1MDQ3IiwiY2xhaW0iOnsiaW1hZ2UiOlt7ImNvbnRlbnRVcmwiOiJodHRwczovL3MzLmFtYXpvbmF3cy5jb20va2Q0L3J5YW4iLCJuYW1lIjoiYXZhdGFyIiwiQHR5cGUiOiJJbWFnZU9iamVjdCJ9LHsiY29udGVudFVybCI6Imh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9keDMvcnlhbiIsIm5hbWUiOiJjb3ZlciIsIkB0eXBlIjoiSW1hZ2VPYmplY3QifV0sIkB0eXBlIjoiUGVyc29uIiwid2Vic2l0ZSI6W3sidXJsIjoiaHR0cDovL3NoZWEuaW8iLCJAdHlwZSI6IldlYlNpdGUifV0sImFjY291bnQiOlt7ImlkZW50aWZpZXIiOiIxTEZTMzd5UlNpYndiZjhDblhlQ241dDFHS2VURVpNbXU5Iiwicm9sZSI6InBheW1lbnQiLCJAdHlwZSI6IkFjY291bnQiLCJzZXJ2aWNlIjoiYml0Y29pbiJ9LHsiY29udGVudFVybCI6Imh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9wazkvcnlhbiIsImlkZW50aWZpZXIiOiIxRTQzMjlFNjYzNEM3NTczMEQ0RDg4QzA2MzhGMjc2OUQ1NUI5ODM3IiwiQHR5cGUiOiJBY2NvdW50Iiwic2VydmljZSI6InBncCJ9LHsicHJvb2ZUeXBlIjoiaHR0cCIsImlkZW50aWZpZXIiOiJmMjI1MDEyM2E2YWYxMzhjODZiMzBmMzIzM2IzMzg5NjFkYzhmYmMzIiwicHJvb2ZVcmwiOiJodHRwczovL3d3dy5mYWNlYm9vay5jb20vbXNyb2JvdDAvcG9zdHMvMTAxNTM2NDQ0NDY0NTI3NTkiLCJzZXJ2aWNlIjoib3BlbmJhemFhciIsIkB0eXBlIjoiQWNjb3VudCJ9LHsicHJvb2ZUeXBlIjoiaHR0cCIsImlkZW50aWZpZXIiOiJyeWFuZXNoZWEiLCJwcm9vZlVybCI6Imh0dHBzOi8vdHdpdHRlci5jb20vcnlhbmVzaGVhL3N0YXR1cy83NjU1NzUzODg3MzUwODI0OTYiLCJzZXJ2aWNlIjoidHdpdHRlciIsIkB0eXBlIjoiQWNjb3VudCJ9LHsicHJvb2ZUeXBlIjoiaHR0cCIsImlkZW50aWZpZXIiOiJzaGVhMjU2IiwicHJvb2ZVcmwiOiJodHRwczovL2dpc3QuZ2l0aHViLmNvbS9zaGVhMjU2L2E2ZGMxZjMxODJmMjhiYjIyODVmZWFlZjA3YTE0MzQwIiwic2VydmljZSI6ImdpdGh1YiIsIkB0eXBlIjoiQWNjb3VudCJ9LHsicHJvb2ZUeXBlIjoiaHR0cCIsImlkZW50aWZpZXIiOiJyeWFuZXNoZWEiLCJwcm9vZlVybCI6Imh0dHBzOi8vd3d3LmZhY2Vib29rLmNvbS9yeWFuZXNoZWEvcG9zdHMvMTAxNTQxODI5OTc0MDc3MTMiLCJzZXJ2aWNlIjoiZmFjZWJvb2siLCJAdHlwZSI6IkFjY291bnQifV0sImFkZHJlc3MiOnsiYWRkcmVzc0xvY2FsaXR5IjoiTmV3IFlvcmsiLCJAdHlwZSI6IlBvc3RhbEFkZHJlc3MifSwiZGVzY3JpcHRpb24iOiJDby1mb3VuZGVyIG9mIEJsb2Nrc3RhY2sgSW5jLiIsIm5hbWUiOiJSeWFuIFNoZWEifSwiZXhwaXJlc0F0IjoiMjAxNy0xMi0yMVQwMjoyMDoyNC41NzUwNDciLCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDMxMmNjZjMyNTVjYjAwNWU0MmMxODZhYTNkMjMwMjA4M2IzMDZhNTJjMWYwY2I0N2IxMTE5NjM5ZjEzNGU2Njk1In0sInN1YmplY3QiOnsicHVibGljS2V5IjoiMDMxMmNjZjMyNTVjYjAwNWU0MmMxODZhYTNkMjMwMjA4M2IzMDZhNTJjMWYwY2I0N2IxMTE5NjM5ZjEzNGU2Njk1In19.YVoNsoJCTMcXIwqa9D5kinkUrnyppsYus7Z-8cn7o9hA6_IG9zkoZGSvsIzfqqjG1mV8JNV1Nh04CZl1qrt1YQ",
"parentPublicKey": "0312ccf3255cb005e42c186aa3d2302083b306a52c1f0cb47b1119639f134e6695",
"encrypted": false
}
]

View File

@@ -1,43 +0,0 @@
[
{
"decodedToken": {
"header": {
"alg": "ES256K",
"typ": "JWT"
},
"payload": {
"issuedAt": "2016-04-20T12:25:14.453734",
"claim": {
"account": [],
"accounts": [],
"@type": "Person",
"image": [
{
"contentUrl": "https://s3.amazonaws.com/97p/rv1.jpeg",
"@type": "ImageObject",
"name": "cover"
},
{
"contentUrl": "https://s3.amazonaws.com/kd4/ryan_apr20",
"@type": "ImageObject",
"name": "avatar"
}
],
"name": "Ryan Shea"
},
"expiresAt": "2017-04-20T12:25:14.453734",
"subject": {
"publicKey": "02413d7c51118104cfe1b41e540b6c2acaaf91f1e2e22316df7448fb6070d582ec"
},
"issuer": {
"publicKey": "02413d7c51118104cfe1b41e540b6c2acaaf91f1e2e22316df7448fb6070d582ec"
}
},
"signature": "Xj3z975ccW6oxbrlm_YsdGNreuzERRxPoj0DyyJ9vygMYfUjsTQGcxsejmkSPYafTFd6TNIbNBTquutOKZvmBA"
},
"token": "eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJpc3N1ZWRBdCI6IjIwMTYtMDQtMjBUMTI6MjU6MTQuNDUzNzM0IiwiY2xhaW0iOnsiYWNjb3VudCI6W10sImFjY291bnRzIjpbXSwiQHR5cGUiOiJQZXJzb24iLCJpbWFnZSI6W3siY29udGVudFVybCI6Imh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS85N3AvcnYxLmpwZWciLCJAdHlwZSI6IkltYWdlT2JqZWN0IiwibmFtZSI6ImNvdmVyIn0seyJjb250ZW50VXJsIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2tkNC9yeWFuX2FwcjIwIiwiQHR5cGUiOiJJbWFnZU9iamVjdCIsIm5hbWUiOiJhdmF0YXIifV0sIm5hbWUiOiJSeWFuIFNoZWEifSwiZXhwaXJlc0F0IjoiMjAxNy0wNC0yMFQxMjoyNToxNC40NTM3MzQiLCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDI0MTNkN2M1MTExODEwNGNmZTFiNDFlNTQwYjZjMmFjYWFmOTFmMWUyZTIyMzE2ZGY3NDQ4ZmI2MDcwZDU4MmVjIn0sInN1YmplY3QiOnsicHVibGljS2V5IjoiMDI0MTNkN2M1MTExODEwNGNmZTFiNDFlNTQwYjZjMmFjYWFmOTFmMWUyZTIyMzE2ZGY3NDQ4ZmI2MDcwZDU4MmVjIn19.Xj3z975ccW6oxbrlm_YsdGNreuzERRxPoj0DyyJ9vygMYfUjsTQGcxsejmkSPYafTFd6TNIbNBTquutOKZvmBA",
"parentPublicKey": "02413d7c51118104cfe1b41e540b6c2acaaf91f1e2e22316df7448fb6070d582ec",
"publicKey": "02413d7c51118104cfe1b41e540b6c2acaaf91f1e2e22316df7448fb6070d582ec",
"encrypted": false
}
]

View File

@@ -1,74 +0,0 @@
{
"name": "blockstack-auth",
"version": "0.2.6",
"description": "Blockstack Auth Library",
"main": "lib/index",
"scripts": {
"compile": "babel --presets es2015 src -d lib",
"test": "npm run compile; node lib/test/unitTests.js",
"prepublish": "npm run compile",
"browserify-test": "npm run compile; node lib/test/browserifyTests.js",
"browserify-app": "npm run compile; browserify lib/test/browserifyApp.js -o lib/test/bundle.js",
"release": "npm version patch && npm publish"
},
"repository": {
"type": "git",
"url": "https://github.com/blockstack/blockstack-auth-js.git"
},
"keywords": [
"blockchain",
"id",
"auth",
"authentication",
"bitcoin",
"blockchain auth",
"blockchain authentication",
"blockchainid",
"blockchain id",
"bitcoin auth",
"bitcoin authentication",
"bitcoin login",
"blockchain login",
"authorization",
"login",
"signin",
"sso",
"crypto",
"cryptography",
"token",
"blockstack",
"blockstack auth"
],
"author": {
"name": "Blockstack Inc.",
"email": "admin@blockstack.com",
"url": "https://blockstack.com"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/blockstack/blockstack-auth-js/issues"
},
"homepage": "https://github.com/blockstack/blockstack-auth-js#readme",
"dependencies": {
"base64url": "^1.0.4",
"elliptic": "^5.1.0",
"elliptic-curve": "^0.1.0",
"hasprop": "0.0.3",
"jsontokens": "^0.6.5",
"key-encoder": "^1.1.3",
"keychain-manager": "^1.1.2",
"node-uuid": "^1.4.3",
"promise": "^7.0.4",
"query-string": "^4.2.3",
"request": "^2.79.0"
},
"devDependencies": {
"babel-cli": "^6.14.0",
"babel-preset-es2015": "^6.14.0",
"browserify": "^13.1.1",
"onename-api": "^1.0.1",
"phantomjs-prebuilt": "^2.1.13",
"tape": "^4.2.0",
"tape-run": "^2.1.4"
}
}

View File

@@ -75,7 +75,7 @@
"elliptic-curve": "^0.1.0",
"hasprop": "0.0.4",
"isomorphic-fetch": "^2.2.1",
"jsontokens": "^0.6.2",
"jsontokens": "^0.7.3",
"key-encoder": "^1.1.6",
"promise": "^7.1.1",
"query-string": "^4.3.2",

142
src/auth.js Normal file
View File

@@ -0,0 +1,142 @@
'use strict'
import queryString from 'query-string'
import base64url from 'base64url'
import request from 'request'
import { TokenSigner, decodeToken, createUnsecuredToken } from 'jsontokens'
import { secp256k1 } from 'elliptic-curve'
import { makeUUID4, nextMonth, nextHour } from './utils'
import { makeDIDFromPublicKey, makeDIDFromAddress } from './decentralizedIDs'
export function makeAuthRequest(privateKey,
appManifest,
scopes=[],
expiresAt=nextHour()) {
let token = null
/* Create the payload */
let payload = {
jti: makeUUID4(),
iat: new Date().getTime(),
exp: nextHour(),
iss: null,
manifest: appManifest,
scopes: scopes
}
if (privateKey === null) {
/* Create an unsecured token and return it */
token = createUnsecuredToken(payload)
} else {
/* Convert the private key to a public key to an issuer */
const publicKey = secp256k1.getPublicKey(privateKey)
const issuer = makeDIDFromPublicKey(publicKey)
payload.iss = issuer
/* Sign and return the token */
const tokenSigner = new TokenSigner('ES256k', privateKey)
token = tokenSigner.sign(payload)
}
return token
}
export function verifyAuthRequest(token) {
const decodedToken = decodeToken(token)
const payload = decodedToken.payload
const publicKey = payload.iss
const tokenVerifier = new TokenVerifier('ES256k', publicKey)
const verified = tokenVerifier.verify(token)
return false
}
export function makeAuthResponse(privateKey,
profile={},
username=null,
expiresAt=nextMonth()) {
/* Convert the private key to a public key to an issuer */
const publicKey = secp256k1.getPublicKey(privateKey)
const issuer = makeDIDFromPublicKey(publicKey)
/* Create the payload */
const payload = {
jti: makeUUID4(),
iat: new Date().getTime(),
exp: nextMonth(),
iss: issuer,
profile: profile,
username: username
}
/* Sign and return the token */
const tokenSigner = new TokenSigner('ES256k', privateKey)
return tokenSigner.sign(payload)
}
const BLOCKSTACK_HANDLER = "web+blockstack"
export class Authenticator {
constructor(currentHostURL=window.location.origin) {
this.storageLabel = 'blockstack'
this.currentHost = currentHostURL
this.signingKey = null
this.identityProviderURL = "http://localhost:8888/auth"
}
isUserLoggedIn() {
return window.localStorage.getItem(this.storageLabel) ? true : false
}
requestLogin() {
const authRequest = makeAuthRequest(this.signingKey, this.currentHost)
setTimeout(function() {
window.location = this.identityProviderURL + "?authRequest=" + authRequest
}, 200)
window.location = BLOCKSTACK_HANDLER + ":" + authRequest
}
getAuthResponseToken() {
const queryDict = queryString.parse(location.search)
return queryDict.authResponse
}
isLoginPending() {
return this.getAuthResponseToken() ? true : false
}
completeLogin(callbackFunction) {
const authResponseToken = this.getAuthResponseToken()
const decodedToken = decodeToken(authResponseToken)
const username = decodedToken.payload.username
const profile = decodedToken.payload.profile
const session = {
username: username,
profile: profile,
authResponseToken: authResponseToken
}
window.localStorage.setItem(this.storageLabel, JSON.stringify(session))
callbackFunction(session)
}
loadSession(callbackFunction) {
const session = JSON.parse(localStorage.getItem(this.storageLabel))
callbackFunction(session)
}
logout() {
window.localStorage.removeItem(this.storageLabel)
window.location = this.currentHost
}
}
/*
request(requestURL, (error, response, body) => {
if (!error && response.statusCode == 200) {
const profile = JSON.parse(body)[username].profile
}
})
*/

View File

@@ -1,77 +0,0 @@
'use strict'
import queryString from 'query-string'
import base64url from 'base64url'
import request from 'request'
import { decodeToken } from 'jsontokens'
export class AuthAgent {
constructor(identityProviderURL, nameResolverURL,
currentHostURL=window.location.origin) {
this.storageLabel = 'blockstack'
this.identityProviderURL = identityProviderURL
this.nameResolverURL = nameResolverURL
this.currentHost = currentHostURL
}
static getUsernameFromToken(authResponseToken) {
var decodedToken = decodeToken(authResponseToken)
var decodedBlockstackID = decodedToken.payload.issuer.username
return decodedBlockstackID.split('.')[0]
}
isUserLoggedIn() {
return window.localStorage.getItem(this.storageLabel) ? true : false
}
requestLogin() {
const payload = {
appURI: this.currentHost,
issuedAt: new Date().getTime()
}
const authRequest = base64url.encode(JSON.stringify(payload))
setTimeout(function() {
window.location = this.identityProviderURL + "?authRequest=" + authRequest
}, 200)
window.location = "web+blockstack:" + authRequest
}
getAuthResponseToken() {
const queryDict = queryString.parse(location.search)
return queryDict.authResponse
}
isLoginPending() {
return this.getAuthResponseToken() ? true : false
}
completeLogin(callbackFunction) {
const authResponseToken = this.getAuthResponseToken()
const username = AuthAgent.getUsernameFromToken(authResponseToken)
const requestURL = this.nameResolverURL + username
request(requestURL, (error, response, body) => {
if (!error && response.statusCode == 200) {
const profile = JSON.parse(body)[username].profile
const session = {
username: username,
profile: profile,
authResponseToken: authResponseToken
}
window.localStorage.setItem(this.storageLabel, JSON.stringify(session))
callbackFunction(session)
}
})
}
loadSession(callbackFunction) {
const session = JSON.parse(localStorage.getItem(this.storageLabel))
callbackFunction(session)
}
logout() {
window.localStorage.removeItem(this.storageLabel)
window.location = this.currentHost
}
}

View File

@@ -1,63 +0,0 @@
'use strict'
import KeyEncoder from 'key-encoder'
import { TokenSigner, decodeToken, createUnsignedToken } from 'jsontokens'
import { secp256k1 } from 'elliptic-curve'
import base64url from 'base64url'
import { generateUUID4 } from './utils'
export function createRequestPayload(issuer, provisions=null) {
let unsignedRequest = {
issuer: issuer,
issuedAt: new Date().getTime()
}
if (provisions) {
unsignedRequest.provisions = provisions
}
return unsignedRequest
}
export function createUnsignedRequest(issuer) {
const header = { typ: 'JWT' }
const payload = createRequestPayload(issuer)
const unsignedToken = createUnsignedToken(header, payload) + '.0'
return unsignedToken
}
export class AuthRequest {
constructor(privateKey) {
this.privateKey = privateKey
this.keyEncoder = new KeyEncoder('secp256k1')
this.publicKey = secp256k1.getPublicKey(privateKey)
this.tokenSigner = new TokenSigner('ES256k', privateKey)
this.issuer = { publicKey: this.publicKey }
this.provisions = [
{ action: 'sign', data: generateUUID4() },
{ action: 'disclose', scope: 'username' }
]
}
setIssuer(issuer) {
const newIssuer = this.issuer
for (let attrname in issuer) {
newIssuer[attrname] = issuer[attrname]
}
this.issuer = newIssuer
}
setProvisions(provisions) {
this.provisions = provisions
}
payload() {
return {
issuer: this.issuer,
issuedAt: new Date().getTime(),
provisions: this.provisions
}
}
sign() {
return this.tokenSigner.sign(this.payload())
}
}

View File

@@ -1,72 +0,0 @@
'use strict'
import KeyEncoder from 'key-encoder'
import { TokenSigner, decodeToken } from 'jsontokens'
import { secp256k1 } from 'elliptic-curve'
export class AuthResponse {
constructor(privateKey) {
this.privateKey = privateKey
this.keyEncoder = new KeyEncoder('secp256k1')
this.publicKey = secp256k1.getPublicKey(privateKey)
this.tokenSigner = new TokenSigner('ES256k', privateKey)
this.issuer = { publicKey: this.publicKey }
}
satisfyProvisions(provisions, username, privateData) {
provisions.forEach((provision) => {
switch(provision.action) {
case 'disclose':
if (provision.scope === 'username' && username) {
provision.data = username
}
break;
case 'sign':
if (provision.data) {
const signature = secp256k1.signMessage(
provision.data, this.privateKey)
provision.signature = signature
}
break;
case 'write':
break;
default:
break;
}
})
this.provisions = provisions
}
setIssuer(username, publicKeychain, chainPath) {
if (username && publicKeychain && chainPath) {
this.issuer = {
publicKey: this.publicKey,
username: username,
publicKeychain: publicKeychain,
chainPath: chainPath
}
} else if (username) {
this.issuer = {
publicKey: this.publicKey,
username: username
}
} else if (username || publicKeychain || chainPath) {
throw 'Either all or none of the following must be provided: username, publicKeychain, chainPath'
} else {
throw 'Cannot set issuer without the following: username, publicKeychain, chainPath'
}
}
payload() {
return {
issuer: this.issuer,
issuedAt: new Date().getTime(),
provisions: this.provisions
}
}
sign() {
return this.tokenSigner.sign(this.payload())
}
}

29
src/decentralizedIDs.js Normal file
View File

@@ -0,0 +1,29 @@
'use strict'
export function makeDIDFromPublicKey(publicKey) {
return `did:ecdsa-pub:${publicKey}`
}
export function makeDIDFromAddress(address) {
return `did:btc-addr:${address}`
}
export function getPublicKeyOrAddressFromDID(did) {
const didParts = did.split(':')
if (didParts.length !== 3) {
throw new InvalidDIDError('Decentralized IDs must have 3 parts')
}
if (didParts[0].toLowerCase() !== 'did') {
throw new InvalidDIDError('Decentralized IDs must start with "did"')
}
if (didParts[1].toLowerCase() === 'ecdsa-pub') {
return didParts[2]
} else if (didParts[1].toLowerCase() === 'btc-addr') {
return didParts[2]
} else {
throw new InvalidDIDError('Decentralized ID format not supported')
}
}

9
src/errors.js Normal file
View File

@@ -0,0 +1,9 @@
'use strict'
export class InvalidDIDError extends Error {
constructor(message) {
super()
this.name = 'InvalidDIDError'
this.message = (message || '')
}
}

View File

@@ -1,9 +1,37 @@
'use strict'
export {
makeAuthRequest,
makeAuthResponse,
Authenticator
} from './auth'
export {
makeDIDFromPublicKey,
makeDIDFromAddress,
getPublicKeyOrAddressFromDID
} from './decentralizedIDs'
export {
privateKeyToPublicKey
} from './keyUtils'
export {
Profile
} from './profile'
export {
validateProofs
} from './profileProofs'
export {
Person,
Organization,
CreativeWork,
getPersonFromLegacyFormat,
resolveZoneFileToPerson
} from './profileSchemas'
export {
signProfileToken,
wrapProfileToken,
@@ -12,20 +40,16 @@ export {
} from './profileTokens'
export {
Person,
Organization,
CreativeWork,
resolveZoneFileToPerson
} from './profileSchemas'
export {
validateProofs,
services,
containsValidProofStatement
} from './profileProofs'
} from './services'
export {
nextYear,
nextMonth,
nextHour,
getEntropy,
privateKeyToPublicKey
makeUUID4
} from './utils'
export {
@@ -33,12 +57,3 @@ export {
getTokenFileUrlFromZoneFile
} from './zoneFiles'
export {
AuthAgent
} from './authAgent'
export {
AuthRequest
} from './authRequest'
export {
AuthResponse
} from './authResponse'

12
src/keyUtils.js Normal file
View File

@@ -0,0 +1,12 @@
'use strict'
import BigInteger from 'bigi'
import { ECPair as ECKeyPair } from 'bitcoinjs-lib'
export function privateKeyToPublicKey(privateKey) {
const privateKeyBuffer = new Buffer(privateKey, 'hex')
const privateKeyBigInteger = BigInteger.fromBuffer(privateKeyBuffer)
const keyPair = new ECKeyPair(privateKeyBigInteger, null, {})
const publicKey = keyPair.getPublicKeyBuffer().toString('hex')
return publicKey
}

View File

@@ -4,7 +4,8 @@ import ecurve from 'ecurve'
import { ECPair as ECKeyPair } from 'bitcoinjs-lib'
import { decodeToken, TokenSigner, TokenVerifier } from 'jsontokens'
import BigInteger from 'bigi'
import { nextYear, privateKeyToPublicKey, generateUUID4 } from './utils'
import { nextYear, makeUUID4 } from './utils'
import { privateKeyToPublicKey } from './keyUtils'
const secp256k1 = ecurve.getCurveByName('secp256k1')
@@ -38,7 +39,7 @@ export function signProfileToken(profile, privateKey, subject=null, issuer=null,
const tokenSigner = new TokenSigner(signingAlgorithm, privateKey)
const payload = {
jti: generateUUID4(),
jti: makeUUID4(),
iat: issuedAt.toISOString(),
exp: expiresAt.toISOString(),
subject: subject,
@@ -70,18 +71,25 @@ export function verifyProfileToken(token, publicKeyOrAddress) {
const decodedToken = decodeToken(token)
const payload = decodedToken.payload
if (!payload.hasOwnProperty('subject')) {
// Inspect and verify the subject
if (payload.hasOwnProperty('subject')) {
if (!payload.subject.hasOwnProperty('publicKey')) {
throw new Error("Token doesn't have a subject public key")
}
} else {
throw new Error("Token doesn't have a subject")
}
if (!payload.subject.hasOwnProperty('publicKey')) {
throw new Error("Token doesn't have a subject public key")
}
if (!payload.hasOwnProperty('issuer')) {
// Inspect and verify the issuer
if (payload.hasOwnProperty('issuer')) {
if (!payload.issuer.hasOwnProperty('publicKey')) {
throw new Error("Token doesn't have an issuer public key")
}
} else {
throw new Error("Token doesn't have an issuer")
}
if (!payload.issuer.hasOwnProperty('publicKey')) {
throw new Error("Token doesn't have an issuer public key")
}
// Inspect and verify the claim
if (!payload.hasOwnProperty('claim')) {
throw new Error("Token doesn't have a claim")
}

View File

@@ -1,234 +1,68 @@
'use strict'
import test from 'tape'
import { decodeToken } from 'jsontokens'
import {
AuthMessage, AuthRequest, AuthResponse, createUnsignedRequest,
verifyAuthMessage, decodeToken, AuthAgent
makeAuthRequest, makeAuthResponse, makeDIDFromPublicKey
} from '../index'
import { OnenameClient } from 'onename-api'
let onenameResolver = new OnenameClient(
process.env.ONENAME_APP_ID, process.env.ONENAME_APP_SECRET)
function testBlockstackResolver(blockstackIDs, resolve, reject) {
if (blockstackIDs[0] === 'todo.app') {
resolve({
"todo.app": {
"profile": {
"auth": [
{
"publicKey": "027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69"
}
]
}
}
})
} else if (blockstackIDs[0] === 'ryan.id') {
resolve({
"ryan.id": {
"profile": {
"auth": [
{
"publicKeychain": "xpub661MyMwAqRbcFQVrQr4Q4kPjaP4JjWaf39fBVKjPdK6oGBayE46GAmKzo5UDPQdLSM9DufZiP8eauy56XNuHicBySvZp7J5wsyQVpi2axzZ"
}
]
}
}
})
} else {
resolve(null)
}
}
function testAuthRequest() {
const privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'
const publicKey = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69'
const sampleToken = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3N1ZWRBdCI6IjE0NDA3MTM0MTQuMTkiLCJjaGFsbGVuZ2UiOiIxZDc4NTBkNy01YmNmLTQ3ZDAtYTgxYy1jMDA4NTc5NzY1NDQiLCJwZXJtaXNzaW9ucyI6WyJibG9ja2NoYWluaWQiXSwiaXNzdWVyIjp7InB1YmxpY0tleSI6IjAzODI3YjZhMzRjZWJlZTZkYjEwZDEzNzg3ODQ2ZGVlYWMxMDIzYWNiODNhN2I4NjZlMTkyZmEzNmI5MTkwNjNlNCIsImRvbWFpbiI6Im9uZW5hbWUuY29tIn19.96Q_O_4DX8uPy1enosEwS2sIcyVelWhxvfj2F8rOvHldhqt9YRYilauepb95DVnmpqpCXxJb7jurT8auNCbptw'
const sampleTokenPayload = {"issuedAt": "1440713414.19", "challenge": "1d7850d7-5bcf-47d0-a81c-c00857976544", "permissions": ["blockchainid"], "issuer": {"publicKey": "03827b6a34cebee6db10d13787846deeac1023acb83a7b866e192fa36b919063e4", "domain": "onename.com"}}
test('basicRequest', (t) => {
t.plan(4)
const issuingBlockchainID = 'todo.app'
let authRequest = new AuthRequest(privateKey)
authRequest.setIssuer({
username: issuingBlockchainID
})
const authRequestToken = authRequest.sign()
const decodedAuthRequestToken = decodeToken(authRequestToken)
t.ok(authRequest instanceof AuthRequest, 'authRequest should be a valid AuthMessage object')
t.equal(typeof authRequestToken, 'string', 'token should be a string')
t.equal(decodedAuthRequestToken.payload.issuer.username, issuingBlockchainID, 'token blockchain id should match the reference')
verifyAuthMessage(authRequestToken, testBlockstackResolver, (verified) => {
t.equal(verified, true, 'token should be verified')
}, function(err) {
console.log(err)
})
})
test('unsignedRequest', (t) => {
t.plan(2)
const unsignedRequestToken = createUnsignedRequest({ 'app': 'unknown' })
t.ok(unsignedRequestToken)
console.log(unsignedRequestToken)
const decodedRequestToken = decodeToken(unsignedRequestToken)
t.ok(decodedRequestToken)
console.log(decodedRequestToken)
})
test('advancedRequest', (t) => {
t.plan(4)
const issuingBlockchainID = 'todo.app'
let authRequest = new AuthRequest(privateKey)
authRequest.setIssuer({
username: issuingBlockchainID,
appName: 'Todo App',
appDomain: 'todo.app'
})
authRequest.setProvisions([
{ action: 'disclose', scope: 'username' },
{ action: 'write', data: { uuid: '34e57db64ce7435ab0f759oca31386527c670bd1' } }
])
const authRequestToken = authRequest.sign()
const decodedAuthRequestToken = decodeToken(authRequestToken)
console.log(authRequestToken)
console.log(JSON.stringify(decodedAuthRequestToken, null, 2))
t.ok(authRequest instanceof AuthRequest, 'authRequest should be a valid AuthMessage object')
t.equal(typeof authRequestToken, 'string', 'token should be a string')
t.equal(decodedAuthRequestToken.payload.issuer.username, issuingBlockchainID, 'token blockchain id should match the reference')
verifyAuthMessage(authRequestToken, testBlockstackResolver, function(verified) {
t.equal(verified, true, 'token should be verified')
}, function(err) {
console.log(err)
})
})
test('requestDecoding', (t) => {
t.plan(1)
const decodedSampleToken = decodeToken(sampleToken)
t.equal(JSON.stringify(decodedSampleToken.payload), JSON.stringify(sampleTokenPayload), 'token payload should match the reference payload')
})
}
function testAuthResponse() {
let privateKeyHex = '278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f',
publicKeyHex = '03fdd57adec3d438ea237fe46b33ee1e016eda6b585c3e27ea66686c2ea5358479',
publicKeychain = 'xpub661MyMwAqRbcFQVrQr4Q4kPjaP4JjWaf39fBVKjPdK6oGBayE46GAmKzo5UDPQdLSM9DufZiP8eauy56XNuHicBySvZp7J5wsyQVpi2axzZ',
privateKeychain = 'xprv9s21ZrQH143K2vRPJpXPhcT12MDpL3rofvjagwKn4yZpPPFpgWn1cy1Wwp3pk78wfHSLcdyZhmEBQsZ29ZwFyTQhhkVVa9QgdTC7hGMB1br',
chainPath = 'bd62885ec3f0e3838043115f4ce25eedd22cc86711803fb0c19601eeef185e39',
provisions = [
{ action: 'sign', data: '7cd9ed5e-bb0e-49ea-a323-f28bde3a0549' },
{ action: 'disclose', scope: 'username' }
],
challengeSignature = "3045022100963da1185591472e1bc867319ddd372593e17758724aaae49a2a30284b399bf0022037022ba279cf20421b96e9cac2a16ab6e415878cda488bc429fbc325f04315af",
username = 'ryan.id',
sampleToken = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3N1ZWRBdCI6IjE0NDA3MTM0MTQuODUiLCJjaGFsbGVuZ2UiOiI3Y2Q5ZWQ1ZS1iYjBlLTQ5ZWEtYTMyMy1mMjhiZGUzYTA1NDkiLCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDNmZGQ1N2FkZWMzZDQzOGVhMjM3ZmU0NmIzM2VlMWUwMTZlZGE2YjU4NWMzZTI3ZWE2NjY4NmMyZWE1MzU4NDc5IiwiY2hhaW5QYXRoIjoiYmQ2Mjg4NWVjM2YwZTM4MzgwNDMxMTVmNGNlMjVlZWRkMjJjYzg2NzExODAzZmIwYzE5NjAxZWVlZjE4NWUzOSIsInB1YmxpY0tleWNoYWluIjoieHB1YjY2MU15TXdBcVJiY0ZRVnJRcjRRNGtQamFQNEpqV2FmMzlmQlZLalBkSzZvR0JheUU0NkdBbUt6bzVVRFBRZExTTTlEdWZaaVA4ZWF1eTU2WE51SGljQnlTdlpwN0o1d3N5UVZwaTJheHpaIiwiYmxvY2tjaGFpbmlkIjoicnlhbiJ9fQ.oO7ROPKq3T3X0azAXzHsf6ub6CYy5nUUFDoy8MS22B3TlYisqsBrRtzWIQcSYiFXLytrXwAdt6vjehj3OFioDQ',
sampleTokenPayload = {"issuedAt": "1440713414.85", "challenge": "7cd9ed5e-bb0e-49ea-a323-f28bde3a0549", "issuer": {"publicKey": "03fdd57adec3d438ea237fe46b33ee1e016eda6b585c3e27ea66686c2ea5358479", "chainPath": "bd62885ec3f0e3838043115f4ce25eedd22cc86711803fb0c19601eeef185e39", "publicKeychain": "xpub661MyMwAqRbcFQVrQr4Q4kPjaP4JjWaf39fBVKjPdK6oGBayE46GAmKzo5UDPQdLSM9DufZiP8eauy56XNuHicBySvZp7J5wsyQVpi2axzZ", "blockchainid": "ryan"}},
partiallyIdentifiedToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDNmZGQ1N2FkZWMzZDQzOGVhMjM3ZmU0NmIzM2VlMWUwMTZlZGE2YjU4NWMzZTI3ZWE2NjY4NmMyZWE1MzU4NDc5IiwiYmxvY2tjaGFpbmlkIjoicnlhbiIsInB1YmxpY0tleWNoYWluIjoieHB1YjY2MU15TXdBcVJiY0ZRVnJRcjRRNGtQamFQNEpqV2FmMzlmQlZLalBkSzZvR0JheUU0NkdBbUt6bzVVRFBRZExTTTlEdWZaaVA4ZWF1eTU2WE51SGljQnlTdlpwN0o1d3N5UVZwaTJheHpaIn0sImlzc3VlZEF0IjoxNDQxNzU1NjE5MDk2LCJjaGFsbGVuZ2UiOiI3Y2Q5ZWQ1ZS1iYjBlLTQ5ZWEtYTMyMy1mMjhiZGUzYTA1NDkiLCJpYXQiOjE0NDE3NTU2MTl9.1LxW_yg2z40Qd84x0kep0-7TWiDdTEoJbdYFUJ3qt297zxbwo8OOvYW43W6TMT5cloxur5wifq0WoOTdXw4C_Q',
invalidUsername = 'ryanshea.id',
privateData = {}
test('basicResponse', function(t) {
t.plan(5)
let authResponse = new AuthResponse(privateKeyHex)
authResponse.satisfyProvisions(provisions, username, privateData)
authResponse.setIssuer(username, publicKeychain, chainPath)
const authResponseToken = authResponse.sign()
const decodedAuthResponseToken = decodeToken(authResponseToken)
console.log(JSON.stringify(decodedAuthResponseToken, null, 2))
t.ok(authResponse instanceof AuthResponse, 'authRequest should be a valid AuthResponse object')
t.equal(typeof authResponseToken, 'string', 'token should be a string')
t.equal(decodedAuthResponseToken.payload.issuer.publicKey, publicKeyHex, 'token public key hex should match the reference value')
t.equal(decodedAuthResponseToken.payload.provisions[0].signature, challengeSignature, 'challenge signature should match the reference value')
verifyAuthMessage(authResponseToken, testBlockstackResolver, function(verified) {
t.equal(verified, true, 'token should be verified')
}, function(err) {
console.log(err)
})
})
test('partiallyIdentifiedResponse', function(t) {
t.plan(1)
verifyAuthMessage(partiallyIdentifiedToken, testBlockstackResolver, function(verified) {
t.equal(verified, false, 'token should be invalid')
}, function(err) {
console.log(err)
})
})
test('responseWithIncorrectBlockchainID', function(t) {
t.plan(2)
let authResponse = new AuthResponse(privateKeyHex, publicKeyHex)
authResponse.satisfyProvisions(provisions, invalidUsername, privateData)
authResponse.setIssuer(invalidUsername, publicKeychain, chainPath)
const authResponseToken = authResponse.sign()
t.ok(authResponseToken, 'token should have been created')
verifyAuthMessage(authResponseToken, testBlockstackResolver, function(verified) {
t.equal(verified, false, 'token should be invalid')
}, function(err) {
console.log(err)
})
})
test('anonymousResponse', function(t) {
t.plan(4)
let authResponse = new AuthResponse(privateKeyHex)
authResponse.satisfyProvisions(provisions)
const authResponseToken = authResponse.sign()
const decodedAuthResponseToken = decodeToken(authResponseToken)
t.ok(authResponse instanceof AuthResponse, 'authRequest should be a valid AuthResponse object')
t.equal(typeof authResponseToken, 'string', 'token should be a string')
t.equal(decodedAuthResponseToken.payload.issuer.publicKey, publicKeyHex, 'token public key hex should match the reference value')
verifyAuthMessage(authResponseToken, testBlockstackResolver, function(verified) {
t.equal(verified, true, 'token should be verified')
}, function(err) {
console.log(err)
})
})
test('responseDecoding', function(t) {
t.plan(1)
const decodedSampleToken = decodeToken(sampleToken)
t.equal(JSON.stringify(decodedSampleToken.payload), JSON.stringify(sampleTokenPayload), 'token payload should match the reference payload')
})
}
export function runAuthTests() {
testAuthRequest()
testAuthResponse()
const privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'
const publicKey = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69'
const appManifest = {
name: "Hello, Blockstack",
short_name: "Hello, Blockstack",
start_url: "https://helloblockstack.com",
display: "standalone",
background_color: "#fff",
description: "A simple app demonstrating how to log in with Blockstack.",
icons: [
{
src: "https://raw.githubusercontent.com/blockstack/blockstack-portal/master/app/images/app-hello-blockstack.png",
sizes: "192x19x",
type: "image/png"
}
]
}
const profile = {
"@type": "Person",
name: "Ryan Shea",
description: "Co-founder of Blockstack Inc."
}
//const sampleToken = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3N1ZWRBdCI6IjE0NDA3MTM0MTQuMTkiLCJjaGFsbGVuZ2UiOiIxZDc4NTBkNy01YmNmLTQ3ZDAtYTgxYy1jMDA4NTc5NzY1NDQiLCJwZXJtaXNzaW9ucyI6WyJibG9ja2NoYWluaWQiXSwiaXNzdWVyIjp7InB1YmxpY0tleSI6IjAzODI3YjZhMzRjZWJlZTZkYjEwZDEzNzg3ODQ2ZGVlYWMxMDIzYWNiODNhN2I4NjZlMTkyZmEzNmI5MTkwNjNlNCIsImRvbWFpbiI6Im9uZW5hbWUuY29tIn19.96Q_O_4DX8uPy1enosEwS2sIcyVelWhxvfj2F8rOvHldhqt9YRYilauepb95DVnmpqpCXxJb7jurT8auNCbptw'
//const sampleTokenPayload = {"issuedAt": "1440713414.19", "challenge": "1d7850d7-5bcf-47d0-a81c-c00857976544", "permissions": ["blockchainid"], "issuer": {"publicKey": "03827b6a34cebee6db10d13787846deeac1023acb83a7b866e192fa36b919063e4", "domain": "onename.com"}}
test('makeAuthRequest', (t) => {
t.plan(4)
const authRequest = makeAuthRequest(privateKey, appManifest)
t.ok(authRequest, 'auth request should have been created')
const decodedToken = decodeToken(authRequest)
t.ok(decodedToken, 'auth request token should have been decoded')
const referenceDID = makeDIDFromPublicKey(publicKey)
t.equal(decodedToken.payload.iss, referenceDID, 'auth request issuer should include the public key')
t.equal(JSON.stringify(decodedToken.payload.scopes), "[]", 'auth request scopes should be an empty list')
})
test('makeAuthResponse', (t) => {
t.plan(5)
const authResponse = makeAuthResponse(privateKey, profile)
t.ok(authResponse, 'auth response should have been created')
const decodedToken = decodeToken(authResponse)
t.ok(decodedToken, 'auth response should have been decoded')
const referenceDID = makeDIDFromPublicKey(publicKey)
t.equal(decodedToken.payload.iss, referenceDID, 'auth response issuer should include the public key')
t.equal(JSON.stringify(decodedToken.payload.profile), JSON.stringify(profile), 'auth response profile should equal the reference value')
t.equal(decodedToken.payload.username, null, 'auth response username should be null')
})
}

View File

@@ -2,15 +2,15 @@ import { runProofsUnitTests } from './proofsUnitTests'
import { runUtilsUnitTests } from './utilsUnitTests'
import { runServicesUnitTests } from './servicesUnitTests'
import { runProfilesUnitTests } from './profilesUnitTests'
//import { runAuthTests } from './authUnitTests'
import { runAuthTests } from './authUnitTests'
/* Profiles Tests */
// Auth Tests
runAuthTests()
// Profiles Tests
runProfilesUnitTests()
/* Proofs Tests */
// Proofs Tests
runUtilsUnitTests()
runServicesUnitTests()
runProofsUnitTests()
/* Auth Tests */
//runAuthTests()

View File

@@ -17,7 +17,7 @@ import {
resolveZoneFileToPerson
} from '../index'
import { sampleProfiles, sampleProofs, sampleVerifications, sampleTokenFiles } from './samples'
import { sampleProfiles, sampleProofs, sampleVerifications, sampleTokenFiles } from './sampleData'
function testTokening(filename, profile) {
const keyPair = new ECPair.makeRandom({ rng: getEntropy })

View File

@@ -2,7 +2,7 @@ import test from 'blue-tape'
import fs from 'fs'
import FetchMock from 'fetch-mock'
import { validateProofs } from '../index'
import { sampleProfiles, sampleProofs, sampleVerifications } from './samples'
import { sampleProfiles, sampleProofs, sampleVerifications } from './sampleData'
function testProofs(profile, username, totalProofs) {
mockRequests()

View File

@@ -4,7 +4,7 @@ import test from 'tape'
import { services } from '../services/index'
import { Service } from '../services/service'
import { Facebook } from '../services/facebook'
import { sampleProofs } from './samples'
import { sampleProofs } from './sampleData'
export function runServicesUnitTests() {

View File

@@ -1,7 +1,7 @@
import test from 'tape'
import fs from 'fs'
import { containsValidProofStatement } from '../services'
import { sampleVerifications } from './samples'
import { sampleVerifications } from './sampleData'
export function runUtilsUnitTests() {
test('containsValidProofStatement', (t) => {

View File

@@ -5,7 +5,27 @@
*/
export function nextYear() {
return new Date(new Date().setFullYear(new Date().getFullYear() + 1))
return new Date(
new Date().setFullYear(
new Date().getFullYear() + 1
)
)
}
export function nextMonth() {
return new Date(
new Date().setMonth(
new Date().getMonth() + 1
)
)
}
export function nextHour() {
return new Date(
new Date().setHours(
new Date().getHours() + 1
)
)
}
/**
@@ -21,33 +41,18 @@ export function getEntropy(numberOfBytes) {
return randomBytes(numberOfBytes)
}
/**
* Elliptic Curve Keys
*/
import BigInteger from 'bigi'
import { ECPair as ECKeyPair } from 'bitcoinjs-lib'
export function privateKeyToPublicKey(privateKey) {
const privateKeyBuffer = new Buffer(privateKey, 'hex')
const privateKeyBigInteger = BigInteger.fromBuffer(privateKeyBuffer)
const keyPair = new ECKeyPair(privateKeyBigInteger, null, {})
const publicKey = keyPair.getPublicKeyBuffer().toString('hex')
return publicKey
}
/**
* UUIDs
*/
export function generateUUID4 () {
let d = new Date().getTime();
if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
d += performance.now(); //use high-precision timer if available
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
export function makeUUID4() {
let d = new Date().getTime()
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
d += performance.now(); //use high-precision timer if available
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
}