UNPKG

aladinnetwork-blockstack

Version:

The Aladin Javascript library for authentication, identity, and storage.

252 lines (193 loc) 9.38 kB
import test from 'tape' import { ECPair } from 'bitcoinjs-lib' import FetchMock from 'fetch-mock' import { signProfileToken, wrapProfileToken, verifyProfileToken, extractProfile, Profile, Person, getEntropy, resolveZoneFileToPerson, makeProfileZoneFile, lookupProfile } from '../../../src' import { sampleProfiles, sampleTokenFiles } from './sampleData' function testTokening(filename, profile) { const privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229' const publicKey = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69' let tokenRecords = [] test('profileToToken', (t) => { t.plan(3) const token = signProfileToken(profile, privateKey) t.ok(token, 'Token must have been created') const tokenRecord = wrapProfileToken(token) t.ok(tokenRecord, 'Token record must have been created') const decodedToken = verifyProfileToken(tokenRecord.token, publicKey) t.ok(decodedToken, 'Token record must have been verified') }) test('profileToTokens', (t) => { t.plan(2) tokenRecords = [wrapProfileToken(signProfileToken(profile, privateKey))] t.ok(tokenRecords, 'Tokens should have been created') // console.log(JSON.stringify(tokenRecords, null, 2)) // fs.writeFileSync('./docs/token-files/' + filename, JSON.stringify(tokenRecords, null, 2)) const tokensVerified = true // this will throw an error if one is involid tokenRecords.map(tokenRecord => verifyProfileToken(tokenRecord.token, publicKey)) t.equal(tokensVerified, true, 'All tokens should be valid') }) test('tokenToProfile', (t) => { t.plan(2) const recoveredProfile = extractProfile(tokenRecords[0].token, publicKey) // console.log(recoveredProfile) t.ok(recoveredProfile, 'Profile should have been reconstructed') t.equal(JSON.stringify(recoveredProfile), JSON.stringify(profile), 'Profile should equal the reference') }) test('makeProfileZoneFile', (t) => { t.plan(1) const origin = 'satoshi.id' const tokenFileUrl = 'https://example.com/satoshi.json' const expectedZoneFile = '$ORIGIN satoshi.id\n$TTL 3600\n_http._tcp IN URI 10 1 "https://example.com/satoshi.json"\n\n' const actualZoneFile = makeProfileZoneFile(origin, tokenFileUrl) t.equal(actualZoneFile, expectedZoneFile) }) } function testVerifyToken() { const tokenFile = sampleTokenFiles.ryan_apr20.body const token = tokenFile[0].token const publicKey = '02413d7c51118104cfe1b41e540b6c2acaaf91f1e2e22316df7448fb6070d582ec' const compressedAddress = '1BTku19roxQs2d54kbYKVTv21oBCuHEApF' const uncompressedAddress = '12wes6TQpDF2j8zqvAbXV9KNCGQVF2y7G5' test('verifyToken', (t) => { t.plan(3) const decodedToken1 = verifyProfileToken(token, publicKey) t.ok(decodedToken1, 'Token should have been verified against a public key') const decodedToken2 = verifyProfileToken(token, compressedAddress) t.ok(decodedToken2, 'Token should have been verified against a compressed address') const decodedToken3 = verifyProfileToken(token, uncompressedAddress) t.ok(decodedToken3, 'Token should have been verified against an uncompressed address') }) } function testZoneFile() { test('makeZoneFileForHostedProfile', (t) => { t.plan(3) const fileUrl = 'https://mq9.s3.amazonaws.com/naval.id/profile.json' const incorrectFileUrl = 'mq9.s3.amazonaws.com/naval.id/profile.json' const zoneFile = Profile.makeZoneFile('naval.id', fileUrl) t.ok(zoneFile, 'Zone file should have been created for hosted profile') t.ok(zoneFile.includes(`"${fileUrl}"`), 'Zone file should include quoted entire profile url') t.notOk(zoneFile.includes(`"${incorrectFileUrl}"`), 'Zone file should not include quoted profile url without protocol') }) } function testSchemas() { const keyPair = ECPair.makeRandom({ rng: getEntropy }) const privateKey = keyPair.privateKey.toString('hex') const publicKey = keyPair.publicKey.toString('hex') test('Profile', (t) => { t.plan(5) const profileObject = new Profile(sampleProfiles.naval) t.ok(profileObject, 'Profile object should have been created') const validationResults = Profile.validateSchema(sampleProfiles.naval) t.ok(validationResults.valid, 'Profile should be valid') const profileJson = profileObject.toJSON() t.ok(profileJson, 'Profile JSON should have been created') const tokenRecords = profileObject.toToken(privateKey) t.ok(tokenRecords, 'Profile tokens should have been created') const profileObject2 = Profile.fromToken(tokenRecords, publicKey) t.ok(profileObject2, 'Profile should have been reconstructed from tokens') }) test('Person', (t) => { t.plan(18) const personObject = new Person(sampleProfiles.naval) t.ok(personObject, 'Person object should have been created') const validationResults = Person.validateSchema(sampleProfiles.naval, true) t.ok(validationResults.valid, 'Person profile should be valid') const token = personObject.toToken(privateKey) const tokenRecords = [wrapProfileToken(token)] t.ok(tokenRecords, 'Person profile tokens should have been created') const profileObject2 = Person.fromToken(tokenRecords[0].token, publicKey) t.ok(profileObject2, 'Person profile should have been reconstructed from tokens') const name = personObject.name() t.ok(name, 'Name should have been returned') t.equal(name, 'Naval Ravikant', 'Name should match the expected value') const givenName = personObject.givenName() t.ok(givenName, 'Given name should have been returned') t.equal(givenName, 'Naval', 'Given name should match the expected value') const familyName = personObject.familyName() t.ok(familyName, 'Family name should have been returned') t.equal(familyName, 'Ravikant', 'Family name should match the expected value') const description = personObject.description() t.ok(description, 'Avatar URL should have been returned') const avatarUrl = personObject.avatarUrl() t.ok(avatarUrl, 'Avatar URL should have been returned') const verifiedAccounts = personObject.verifiedAccounts([]) t.ok(verifiedAccounts, 'Verified accounts should have been returned') t.equal(verifiedAccounts.length, 0, 'Verified accounts should match the expected value') const address = personObject.address() t.ok(address, 'Address should have been returned') const birthDate = personObject.birthDate() t.ok(birthDate, 'Birth date should have been returned') const connections = personObject.connections() t.ok(connections, 'Connections should have been returned') const organizations = personObject.organizations() t.ok(organizations, 'Organizations should have been returned') }) test('legacyFormat', (t) => { t.plan(3) const profileObject = Person.fromLegacyFormat(sampleProfiles.navalLegacy) t.ok(profileObject, 'Profile object should have been created from legacy formatted profile') const validationResults = Person.validateSchema(profileObject.toJSON(), true) t.ok(validationResults, 'Profile should be in a valid format') t.deepEqual(profileObject.toJSON(), sampleProfiles.navalLegacyConvert, 'Parsed Legacy profile should match expectations.') }) test('resolveZoneFileToPerson', (t) => { t.plan(2) const zoneFile = '$ORIGIN ryan.id\n$TTL 3600\n_http._tcp IN URI 10 1 "https://blockstack.s3.amazonaws.com/ryan.id"\n' const ownerAddress = '19MoWG8u88L6t766j7Vne21Mg4wHsCQ7vk' FetchMock.get(sampleTokenFiles.ryan.url, sampleTokenFiles.ryan.body) resolveZoneFileToPerson(zoneFile, ownerAddress, (profile) => { t.ok(profile, 'Profile was extracted') t.equal(profile.name, 'Ryan Shea', 'The profile was recovered with the expected value of the name field') }) }) test('profileLookUp', (t) => { t.plan(4) const name = 'ryan.id' const zoneFileLookupURL = 'http://potato:6270/v1/names/' const mockZonefile = { zonefile: '$ORIGIN ryan.id\n$TTL 3600\n_http._tcp IN URI 10 1 "https://blockstack.s3.amazonaws.com/ryan.id"\n', address: '19MoWG8u88L6t766j7Vne21Mg4wHsCQ7vk' } FetchMock.restore() FetchMock.get('http://potato:6270/v1/names/ryan.id', mockZonefile) FetchMock.get('https://core.blockstack.org/v1/names/ryan.id', mockZonefile) FetchMock.get(sampleTokenFiles.ryan.url, sampleTokenFiles.ryan.body) lookupProfile(name, zoneFileLookupURL) .then((profile) => { t.ok(profile, 'zonefile resolves to profile with zoneFileLookupUrl specified') t.equal(profile.name, 'Ryan Shea', 'The profile was recovered with the expected value of the name field') }) .then(() => lookupProfile(name)) .then((profile) => { t.ok(profile, 'zonefile resolves to profile with default behavior') t.equal(profile.name, 'Ryan Shea', 'The profile was recovered with the expected value of the name field') }) }) } export function runProfilesUnitTests() { testVerifyToken() testTokening('naval.json', sampleProfiles.naval) testTokening('google.json', sampleProfiles.google) testTokening('balloonDog.json', sampleProfiles.balloonDog) testZoneFile() testSchemas() }