{"_id":"@globalid/issuer-toolkit","_rev":"132-c2ce699b478ff10a021361c84696f3b6","name":"@globalid/issuer-toolkit","dist-tags":{"alpha":"1.4.0-alpha.15","latest":"1.4.1"},"versions":{"0.2.0-alpha.1":{"name":"@globalid/issuer-toolkit","version":"0.2.0-alpha.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.0-alpha.1","maintainers":[{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"gid-mykola","email":"mykola.mailo@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"andrewglobalid","email":"andrew@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"anjamurgelj","email":"anja.murgelj@kaldi.si"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"4e10083f545f34c284a803ea4ec3ebb79d6911f5","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.0-alpha.1.tgz","fileCount":55,"integrity":"sha512-GMJXzvJp5GmwS06cX4JDthqOzVnBUrlnr1dn6yk6z+Ktx1N6tHXqJpghWAK9iAXYN+PLrxXoGjCPtu52bhqZ6w==","signatures":[{"sig":"MEUCIDDt1Zw0y6wx39sXomCGBKoNw2vDu4cn4novx+HBF759AiEAsXfMlJ4zEIIBlAw6YqD9f499N1pUDsS4Z1df2CCMz/Q=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79105,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8BRbCRA9TVsSAnZWagAAEpsP/19Qvpx6jwenDtybRZfo\naHhE+V5qx/aHUN3FxrtrvtQ79rAXgh67h2ad2hNzFv41UVMcDAqDOotD2xcT\nmWoRoIlHk08ZLQkBswVGXUC+iAI1Qgd6/X7MqvZPplTFOrvUL2u+Fp0mRqGh\nalTD9YDx3zbo75WyLw12qjxXJyKUPzIHrvBbdSkYgY0VHhLY/grc80Oj6cTl\n6uPBh2093Zac8QQ8m9ZUmAXURp240xfk9wEHRPntvY/7F/ta9Ywq1wH7o/MC\nK4mpCOfmGkbokvBgveGfI0DdxvMGjhskx6lF0d0Wo0L7xpN9DB7v1lCu0Kvo\nr6R2y/qBWW0LJ3e/IMSgTd3uLju+WuzHJnKdQmxPwoPE+RQD6tKsvVLDTW4o\n/BCEgK40+TyZJI7zkDFZNPrzcoeltisHWQv9TX7tnr02Xl/SJ903bjtU7arz\natiJ4Km1z6SgdLrS4EGO2LKQ9ENk45A3OqmbEljz3eXdvI55gPRPUj7D0kNf\nTjRms/ZRnHMJ0hvRIRJVsvz5NTv9nG7xssI//gwGctTJ2xi1gGeGNTWBkbdm\ndoxGxnz9+RYX/mmxb0xeOWDXBnOOlT8cwPuNprFoAn7rzNh36o2ULcWcWlfy\nApP+6ADImU+rbSNzh/HUJWlKTLAwZ+LXL+qjQk7kMELdRuipRw2RPRBOJGq8\nKftu\r\n=X7rG\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"a63b711514c9dd33fc64ba96d46a296491c2a346","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.1.2","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.13.1","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.0-alpha.1_1643123802928_0.7210699396613407","host":"s3://npm-registry-packages"}},"0.2.0":{"name":"@globalid/issuer-toolkit","version":"0.2.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.0","maintainers":[{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"gid-mykola","email":"mykola.mailo@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"andrewglobalid","email":"andrew@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"anjamurgelj","email":"anja.murgelj@kaldi.si"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"6fe9cfa57538fb00bf471b5b7f1c4f7848532925","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.0.tgz","fileCount":55,"integrity":"sha512-ox6Ku0+tTyhtwI3edEzE8hI7ZPG/AyRyDmqvt6xTzGkWK6aOsKSrtLR6O3qrsuh6QaiTi2I42Rql2jbvsaZ5Kg==","signatures":[{"sig":"MEUCIQCrHKNP6g0iH1+EUtsB5uxqGSLIJN6HmAio89aqcP8GEAIgf5hjox9UGxMaMA+LZIcni/Zi9xZKqOQTXL3h+o09zBY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79081,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8IVsCRA9TVsSAnZWagAAmcsP/1VJod7NDGXBDp9EjBj9\nHfp/R9y4yNiG2V+5LwFUSW6uqv4wocpFjtvWzlFeDykBMfNlmOvp7VpbZsDi\nWfi1sJcRJW71vLm4G48/QWY5f4XPpORTWLJMqM8OA1ppx4qOCv06n7amyk/S\ntj8Ym33yaDyTYTQXeiq1u7+wyAtp939IB4cacfxzn6ni/NJIq2WqFWBbLIC+\nKpFhMf2XDLkozCmq63FszcoFXOhyoETM5tUs6WvSgzxZB3seC4JhaYemOVee\nUcvt+RM/mS7k3etzK/K0QvkHuf0B5lX6BkVnlvzlc22qxyXU69rGGbd2BzE8\nvWyNIf1ZIitp9DPiG+SnF9jEctwGdB5vzcmE44TCQwq6eaWFB5C15OkvNbhE\nfqJJGFnH46D+C4W1CHWXycjcBco0WfG3G1uYm0UTjtCezheUnaRXVx7JfXuJ\nlFPvV4/Zd8rpf0jyDwuaucAAXsjtinEszOEmmEYEOt51E+EDLIifB6CT8iDj\nECo+PjkE/AuuGMG0Goz3fdUqvLaxu4a9rAML/GjPvC3YomrwxHAvi1u9Jp0A\nY+kN0IAe9j4VsKaPH/UDiI4K/v4aXatG+oqsatCT6KjQRrSxZouMq0aH+SGR\n7+zWW6Xvrx/CFSfBwVZcKi0gu186wqYoNC1JQrHjbwSqMQD971oy3McDwJWe\noyHC\r\n=lQ6m\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"5c889638ed0e45d05de3cafd775f75a3ff195952","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.1.2","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.13.1","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.0_1643152747816_0.5872852669846176","host":"s3://npm-registry-packages"}},"0.2.1-alpha.2":{"name":"@globalid/issuer-toolkit","version":"0.2.1-alpha.2","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1-alpha.2","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"a5fc3de713549bf85c3c6265325c31557bfbed66","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1-alpha.2.tgz","fileCount":55,"integrity":"sha512-0QvQBWkrAKo1+kCga9SOmFBKmVo7xPsa7TwU6UalZewrE9KG4bAlo5rzi7v8oOyOLk9jbBqdvaJXPr+Dyp0fMQ==","signatures":[{"sig":"MEUCIHU6t3fImH9nOFgXHDHUnUJlPQ3v3LR7/ari9tQW97AAAiEA91amRha9H1AjExLzKS0UQNxFcX0XWXXG+0BCcop0Plc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79270,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJ4NXACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr6zA/+JmcrZUviKGLsvvpFkKVdCcTWNWdKSumUq698H/XmangpadNc\r\nsuvkkq0nZIrO+ckqq4jd6P0DuIRbq9Hnyo74MO971SczJrtem+Fy61l7x1Gw\r\nF0mBTTtoY3doiqySuq5ts7baypoMRXIV66zu0Nvq+V1dZE2xtdJ96fZAqS2s\r\nwmtU8yhErkthvGjzSGKNHLDYV8Cd6PRk0+MMT2mHnrcNTCoDbXHLTjQWEiLR\r\nQXcI3uiwQ0TmH17bAxAwBUKTY8sBi3IIjPMC1mkGFfsdz7VODdKRoHUczQK2\r\nOFYryJO4wTtRSI+mpS5bKY/ruV4RhmT1IjdL/+uCZwAnj9M7q35xOLzh+1st\r\nWgTNkyuscwmQskjnsDAhVrbt9V1VVo7Cv7/hmaqIeYbrJsYdCmtis0ftV+W1\r\ngwa4RCAOOedqVkRxXARvlrufNQ9S94EfRFt2xYqRkOxKcEt+6M2+Y24Q6KvU\r\nFAuaLnjmC0W1H5A+NZz6geW4lRleCDmFkXbkK59bmnb+L0Q2C2tfHYiTluYh\r\nauObGx5kJfktFvsU1xJwOKt3qZPKk/oGiQkfG1m503buSQSAsf/I7SAcQYbE\r\nNpG3pYNW3PqVJbPZ4h0L6q64M1PyVvoZ0by1ctVdLitauF15dgW2AYQld1t0\r\nBqwmODiSexvM2mLpER1Y8IWJD1UGtyQlNC4=\r\n=BlHd\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `threadId`, `timestamp`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"9462f5f4399e73a59bfe4aab9dce02100211488d","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1","@globalid/identity-namespace-service-sdk":"^2.2.3"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1-alpha.2_1646756695635_0.25024702759764006","host":"s3://npm-registry-packages"}},"0.2.1-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.2.1-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1-alpha.3","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"d74cb9743551ae8d199178f97a30a0c244f72703","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1-alpha.3.tgz","fileCount":55,"integrity":"sha512-cuPm+gDLJ6bbKq7UUb/y20+lbovLgGm6Xu2CnXVmA3jufzOnh2dVdRmUOvVGJ0yEXogDnXNjA9qsf1lskVh1fg==","signatures":[{"sig":"MEUCIA2whavc6u9Clqn5/c36/o4vw788rpiCadeqvd1GViWOAiEA6hN0y1dyg+MtoWhb0Ft6YGnIsfr0wSgzxNi+DLf/bKQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79357,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJ52MACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqZAhAAoaHuDbOuAcUV4XOripOlT1dCw4jLAGog4jAiMmHvwGARQm6o\r\nvFnlXHoH9zzZ2QuMMWxhTPK8k2c65riyEWlQoq+zaK6JupRz1JvkTB4BHtBF\r\nFzXu4+ukzVTQyzz+HCjsmhURogcKt4lAuHmL6QXBfwsmndDnILSGnu384rh9\r\nCSP+tp7AyaQfZsj1IDf5IZvct0u9hRU6PrVmT03vaH7aMUFZthTW2YRYfwx2\r\nMSiabXVBjXqEB2XNak9WZ7HLeaUhf+xHuYiZJ4+2OeYJSTdXuykBH2gPEpnZ\r\n0FchWC4If9OKSBxxWcHvD0db9CHtXC/aqfi40F6OVQpOgSheLt+fNdkt/lLJ\r\nQBBvU61v8QGB71Rhd+6zeqGKQLuzw6yb3K2VO38KYfXJqGg2shwJ8UUsKPG6\r\nYJbPplwzpIOtC8sWx7AMTK2+gT68Js7oHHA9/HpqdyRrymYQS7eqSsrSLlsX\r\nRH8yiU65LCyON6P9q6JppRrcvvgq3xj1R4iZmFNWo9szzWLUfag7RJndCV4Z\r\n+Fmh5I8BeAJy5m/YxSiMu81wCMPnYj+XKLeVChySKpi00TMK1ExyIe7rBMJj\r\n22qilUJCQRqnwPeho6amngLWEh8ClhRGrgPc1ZRM6K6urQIYxfTo2Et+pVNx\r\n3TS3E4X5J5/IaXZRO6pO75wUTP3FNPh+rHY=\r\n=VyiX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `threadId`, `timestamp`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"6415bb7419cdbdf9d8715a7d706b529b96b897ca","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1","@globalid/identity-namespace-service-sdk":"^2.2.3"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1-alpha.3_1646763404026_0.5272726824716234","host":"s3://npm-registry-packages"}},"0.2.1-alpha.4":{"name":"@globalid/issuer-toolkit","version":"0.2.1-alpha.4","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1-alpha.4","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"3fbab650db7a4765a93735d2c23039a81f98f199","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1-alpha.4.tgz","fileCount":55,"integrity":"sha512-PCoeNOUDwrOCuQWYflFfqS7z7oNoB0J8b7PkNsgA6cMX4Ca2pmhaRAVgrXRCtIYsFW3/rQwiAm1QwgFdZwbdVg==","signatures":[{"sig":"MEYCIQDwWytjqTzu1ASVaojCQMFnnmz36bQY5FshBLNxH72iQgIhAM/eay7UHdohtZex3jBOyOnAJRZ/nxbrMIZAuJJpWc84","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79356,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJ+JhACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqsYBAAo7Zc3A6eI1ivTLaZlIOqkuiGS2Xybxh07CynT2o4q8vChj/c\r\nH33AgnC6aUDfLrYbE+7QfmewqTaYv1ZOzzR81fGC8SmyAjHUbByhFymhA+Pn\r\nH/BKEUQ84Z2zSpFgyk/E9C798sZMrgzK+csC9CGjDkxLNfivX2sF5w8m+kfC\r\npDrsNKR4z8AVpZA883/9JozblIBNZUVXmkvDf4cKeIbOfIreRNP3kWCxykX/\r\ndeKNkNWRN97zwUqe3Trh73GbQvBjSJ+5TLiDNqyOtlBOOJMueXNPzzz2llSq\r\nlaOWjRCPUaiXfuRhB+YweVexXcfvxXR4DzhjA3U8Bvn3eoWFxXJl+IjDwNSJ\r\ncFVndPWwq87BW+Ye19SvroHFl2vT6eDdz95YjqAUsn7flGCRKOXwDACiJwBU\r\nZHpaj48CCMYEz7aGJVFujfBW30ZG5nKFfw2LqQGCxvwpawMR3Xbp5/2SBURX\r\nmXqlUslrcYadGvUpOZhP3+9v5BMxsh/uEOkTTRrr+k+jnHXkH6rlnhqwdkYj\r\nrucPsQyR6kCJtIQAYXTX0N2xRUtbW/+cUi2KbGSNqk9fco3osyOUDGpKUx0h\r\nU9tW9xZTO+8Bv4sdTtOwWZ6pfFUnySbx8JE+nPEvjQ+n/9wgZ5TvU8JvJ4tf\r\nZ49HFz244BxMRgSeVrq4dtaiIdRqlUdnRfM=\r\n=qYNa\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `threadId`, `timestamp`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"4f7708783eae54426d948b9588b9997b1cbc6d94","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1","@globalid/identity-namespace-service-sdk":"^2.2.3"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1-alpha.4_1646781025269_0.13338271267638135","host":"s3://npm-registry-packages"}},"0.2.1-alpha.5":{"name":"@globalid/issuer-toolkit","version":"0.2.1-alpha.5","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1-alpha.5","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"34af3c0833ad948c999760da667030388bd761f0","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1-alpha.5.tgz","fileCount":55,"integrity":"sha512-Qq6M0ItXT738BOhyrhRXWZfxyO24y4la/HItYwho0mPOxsivfz8lJpMAfzKheFC6ajwxhP5hJJFf6XKvqwqNIw==","signatures":[{"sig":"MEYCIQDZ3UdSWmZcOkt52wubxQnP1dUjNoidAOY64f9VzmFbzgIhAM4gW1Pp3vpsRyibXgzl8/nsv01b+FNS1gHLDEzN0n6C","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79353,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJ+fbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrUMBAAhRKhEPjiLpWNWMZqmHDgSjXulYwVXz18OClVe/DiVwKqLHGz\r\n/eJMOJ7EwLYdroPV+nzMSFRO6XTMEUMvXjhKbzqGFGnCT4i6adRKa68ixvOq\r\nsy7inIZD6qHkvfz7AVKSEZ2nbReVrvfB88bfsILq05+6/M40pNtlEdTpZQuv\r\n/awYbPa/d9SdFo1TU1hm5pnac9807lQ5VTGETlk7sXWsu1zm04TtfPoyX8Vy\r\nbG1tkBvuK0rDt2A/47VgQ5hZ7JhCEfF7XZrRZZhLphfiJ4QcFJXm6Q/wFkHO\r\niqjFvSW5lJ3V7UcpmrWviwpZmQylAse5RCL19kn4Hy1V+71z8StGDg2FWEhg\r\nmhG+ng3ecTh+iTPKf6aqpNWUTwBX40Sv3Fz+1TPJdxc3QD9JoH6D8QOR1O92\r\nIUQk+qPHXm1eKVO5MXwELlj+q4VREvEeJbMIHfUd4wqKANV1yPPCOt38ZlPy\r\nLtQovFs6yIEBRdwBwwOQuM0e9RKMvXjWlfT/tTqDqGq18nu7L2j//QG1VGAN\r\ncEiwoeO0dHTt0tz0ew9Hbh22ZUwlBtYXiMDQ5PV/VVIC7rfvm5PJBvGZS1NR\r\nDYZ9LTo97jbe7uVb55hHDfOzvC6OplnHLXRyvhPlrRcwoHOxXmSr3BULnHm2\r\nqoeMLmzfD1c9tuE36ic/Ax9PgselAlR/Ccg=\r\n=WMdG\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `threadId`, `timestamp`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"03e8b3f95311dca28efb57251c91d89216edfc1c","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1","@globalid/identity-namespace-service-sdk":"^2.2.3"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1-alpha.5_1646782427527_0.8984085578487604","host":"s3://npm-registry-packages"}},"0.2.1-alpha.7":{"name":"@globalid/issuer-toolkit","version":"0.2.1-alpha.7","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1-alpha.7","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"8d8ccf0fdfa68fc77d8a799403e772657021a55a","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1-alpha.7.tgz","fileCount":55,"integrity":"sha512-rV66aSCt/oaTky+ay0xAZXo4AhwoJ7jWR8TQApcydA9lXI5pS6SrCU4bdBJHoMzZYbltWi/306WNGX0vdb3RqA==","signatures":[{"sig":"MEUCIQCZcVF6UgkIzzffhaocfD9+VrFO3+c0XNzYdE2yJV6ySQIgXyeusNnryqEE/jZLZrv3k553YJVZoI0djc1O8VQodwo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiKO9xACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqccA//VHefJD3hcljWbNjXdUEC5Ce2P7OOYQPiAZ9USas1JPH32t2c\r\nTMWIFykGWD7EqQAWPrgVV6ZZ1EB75R4Ggk8En1CXt0tf5aUuzEgbYwrE5LQ6\r\ntvCfBDiOxtVAqYWjT3N4TcJxjWeFWEDpq64GiWiW2beMI8kZIrliuKspKEY9\r\nsZinI4VSQZpD8rPRdo0BlgQbhbywqwdBYmukY7Yd5PSay07u9hO4th2Pophv\r\nsP56BQjJSx/UbC0MhkKLjy/iralpUVil6GGrPvcaf7oyI6C0sgcsH/h/vdhM\r\np56L27m3Es8AkUPxJGgk/An7AACBzdf69zJ+1ieYFolUKVeIN9c71PGvNIYn\r\nmd6yqLpvyDsS/SO55Sade6gCo6ohg4NHiK1klDH5QVb5u4Tqi2MVVUm0DVHE\r\nnQVB74nb/EJeXu0Shg6syvK4KTAQmCQlGaLWqbpyPlVyaJrDC3TaLFS2UBco\r\n2TV48Ag2qDUldlJzNbEPqF+RNTaSKcYFOJsKLNG14dSnVAnBe/5x3oso4qvT\r\nm4boJwXYO1eIT93+vioQHZvFAQ4FmEJC+trZ/sIJeTANcFG83V4jiPWhGOpn\r\nQU4BuOokn0ojtW0n5Tim+sFiVLC6udI+oLAulx8rz6xwOB/pv/2h06Sngh4Q\r\nRPYyFJdh0XHfJcFvnO4VcJXfFhA+2mpsh3w=\r\n=LCF7\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `threadId`, `timestamp`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"9bac43ccabfd52ce7892d0819e086d4eaf706283","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1","@globalid/identity-namespace-service-sdk":"^2.2.3"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1-alpha.7_1646849905319_0.692247162766543","host":"s3://npm-registry-packages"}},"0.2.1-alpha.9":{"name":"@globalid/issuer-toolkit","version":"0.2.1-alpha.9","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1-alpha.9","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"d2b3d86730692bd574bca35fdb74044a662797f5","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1-alpha.9.tgz","fileCount":55,"integrity":"sha512-PWm0dfFgeioPUUnEaq0e50MrWBx6PAW8ylEQg/q8FSnc3SIyFIy5j5IIvdmHGKQ8VFD/P1xbpDFM5Flleu52pQ==","signatures":[{"sig":"MEYCIQDJsWYzpSYt+luPvbrfRSHlHhHjgIxYRyHHk+U5/tuIaQIhAN+CCLfpjQyM8zDCaKcpFcv2ADgHTsB4X3+EJXDVU5f6","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79224,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiMMUGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpWSA//RSMR9fZUEuZFIxy3Uc6BAsAjXqKuuSCoy3WQ5Nmdqr4uHUn3\r\n4cPnE3u3aqIHEbPRXDhr3AoSVdrfrDPB9peLFIqHOAYfO7X3gor/gu+IWuV5\r\nvyxvXQzMmmVOXQWxCSTxNdt7VT1AEMKaaiqlk7qeM+T1B5ATNTkCe3pDLXtC\r\npvGGSQ5UcaC3S5WQhNitmyQgfZYtj9U89oK+Swyj6C92uMHyzocROGAYAsmQ\r\nrWlz2xhOOtv3utHprV+Hojo8JYLzxlh2AxEQ7j2QvG9LGAPEXzABYNMAr/F4\r\nLVSDeSwbU6Cbz9+bVWgq1m2p2FGst+UqXC+rJP+ApW2IR4zhtfvTm6KB/4MR\r\n4hnz86a2eAQLk4y86XSZroaF4ybHlu4aQHKOSoB+oIfjHKXfZCiCavlA+p2D\r\nQY7h1rB+GVWe52dryogi5/SyG5fi7ZUblVyGTOh98QnT6qm8GrLyRqfM2W8y\r\nekbgFWEy6cX5/EEoqlMj8D51Su8F7DAZ35wt+6Gb9OdVrL9J7bvm9OfVf2/O\r\nHwuQvTjo4+RI/NFbCb1IAdHGaV3zF8QRZxV+1cdj1w1BS225PRo0nFE7hpgd\r\n8I6QolsyR1w4JhkaZySows0jjsiyPgqFd+fwaOyBnFVv3kdedcgMDPonXzfc\r\njF6BQmbNY6QfmP2EoaBSWMLfHV7em1kPld8=\r\n=zLPr\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `threadId`, `timestamp`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"df554506b06f70a32b6aa9562fac08097cf5fa42","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1-alpha.9_1647363333881_0.9862249434324233","host":"s3://npm-registry-packages"}},"0.2.1":{"name":"@globalid/issuer-toolkit","version":"0.2.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.1","maintainers":[{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"f3829f4ca77ef0405ff6a19b8515cab4676dd89c","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.1.tgz","fileCount":55,"integrity":"sha512-wNFUt2NfTbWfTZ1iYBhMOpBaNKssdLs4W1le0eRP3RNGKUcuD+3ngliPFlX9o9u0WhpRXtCDo2PK5gIvexz3Vw==","signatures":[{"sig":"MEYCIQD+k6uNj8g/cCtrNu+3WOpjex0redCL+zdHu/qcgk/R5wIhAJ9Xy6ng2ZpQwUBgG9KkD7/QA0KXuC+eY0OIcoIbZGgo","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":79032,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiMlDKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp7Pw//aM8dWnhv/ksJBqACumejucMyGAMwXJhb5Pf3j8LW9oigHbsf\r\nI6weg+tppQTvoJf72jxM+sIPT5JVqTGRNjgK64d/r2G1mWPm4v0o++p/Qtrc\r\nUaypSeHKzV2Sgx2OZKNzQ39/MzbzSBswdG9XdLvDyjHEqVTEWXVPpJtD/RKF\r\n7B5CF1p7IkD2OOkaDMuhY2JLgk5oQvY9NoPOIqCBsgdFwe9M/8xHDmMrRV8x\r\nK1OUoswLCSffWlFEo3ERDh1jyG6Ff2x2CIfKNHVFU0tyegH1MnJIitj1eF1V\r\nQdvunwGLYC4XReylB5ooSRyPsX2z2V54WAQjAOTdtyeH+yG0w52rHFpzrVp/\r\nm0DK7IoVnbO8I/o688F8+MovHVWRCnDaE3zKJ0wXzd9xjduu2PzPFiiCPdVr\r\n7iAh1xUmSemksCeE1GJqCJh3bwpl1DR+i4+0ioDrYch4lv2Y4DWdT1ODAcym\r\ngCx02AfINF+YeEKCiNK+ywe1up0Iquj9zSc3dbfkr02X9OfDtRIotyda8SNw\r\njufvC4hFhnt1XLtMwZjLqyuWDb+bQn926EAFYDhZIcEpgQiXYNd1epDNmg7q\r\nT+6AOiOS+ouERREg6z4hTOS48YAViX18GjRgJe9GiqCR9b4O78CBxc/vBe6X\r\n01XeqFA163KLdHVRLk5e8bqpNHFkuhJq5rg=\r\n=Bb5z\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"4a9a1d69e9fa6477ecfee630d462628283c42d4b","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.3.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.1_1647464649656_0.43432251070571737","host":"s3://npm-registry-packages"}},"0.2.3-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.2.3-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.2.3-alpha.3","maintainers":[{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"yrkan","email":"yuri.kan@global.id"},{"name":"yuri_global_id","email":"yurii.yefymovych@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"jovanovska","email":"jovana@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"kristianzupan","email":"kristian.zupan@kaldi.si"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"_igork","email":"igor@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"d23a628a8141b9101dba119c54814408003a5c50","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.2.3-alpha.3.tgz","fileCount":57,"integrity":"sha512-L3iFzrPQofykHCO0A69Eh/8pLFg2HjIpf5VN07bXrKc462LNIjZA74IcGKLLpi3z6AWC3bc/gPp05F8aYf9Wlg==","signatures":[{"sig":"MEYCIQCp1vwkMobNQcGkJnqmc4dR0R7FlpX/L+Xmc8RbxBD1WAIhAOpP7VntHYKrwvKPWmxYelg/OBjrAGGU8tvMGoOD3wgI","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85833,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiVARjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoVyw/+O/ODDeLpUKZhzbde2uDnFWV5paPX4H0aHeQmZoqUwAeHT5uZ\r\n+1SfKahlFirN2vS0UUOyHf1ZhImjp0Tsy25kuk5wbz1EnzbpbzZrlnADGhlT\r\nDvZm9WMO4flnqupwm+BS2YZf4XQVVWxb+04/DPDVScqwm5HhOddLgutGBhmF\r\npRGOebLh1eYHorty/PeiAVP9m2fZ8od/ayh6Y+srACPm31kif9T4pXNm2Rie\r\ngMmN8k/ZKdq/ACVT0r3skFS2BBkxZawIwu+bO9isDTisEVj67B9/tUph2GVW\r\nK1oDWn7DXyM28lVMOimn6Nrra5+U+iR7seRi3LtwHY2jJA1tGb7ElzWCuIdS\r\nbbBX9sWroLnNSIhGX6nfg5+cIjQUTvUdbzraIPVCLwiXKQLBObMGx7Tg14Ws\r\nohj/L5CBE6ntZJXl+Zur0pv4GPF9stUCAwnHImjgltP4NiTohXNnlgyoIMaq\r\n3KtYOiliZFSs93aMzMQgetI9m9mRbNtEc6SZdG+CCn9MSX4iq/gGRBgCm359\r\nER/s16yMqrCKTrnL14pKnYIVxSo8Bscxzmivw1g5w+Zywb3RtMQTsVYrZJol\r\npNmVw8+XhXKWmn2lk6yDrwbgSuCFNbw87X/fUc2SUvwS/Lh5LYEvNKjriObq\r\njFJdI2Q3wsIm3KjyMdtJ/Bb0hLhipzuGMS4=\r\n=opUT\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe constructor requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = new GidClient(clientId, clientSecret);\n```\n\nThe `GidClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidClient`. There are `mock*` functions for each `GidClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidClient` stub.\n\n```js\nimport stubGidClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidClientStub = stubGidClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"f2dd2b172437ae652d1a8e70d4a89251ed114508","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.14.2","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.2.3-alpha.3_1649673315385_0.4391467790725545","host":"s3://npm-registry-packages"}},"0.3.0":{"name":"@globalid/issuer-toolkit","version":"0.3.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.3.0","maintainers":[{"name":"danijelm","email":"danijel.mestnik@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"yrkan","email":"yuri.kan@global.id"},{"name":"yuri_global_id","email":"yurii.yefymovych@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"serhiy.lymar","email":"serhiy.lymar@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"lukafurlan","email":"luka.furlan9@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"p-stav","email":"paul@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"vidp","email":"vid@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"spacemandev","email":"dev@global.id"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"antoinenpm","email":"antoinebonnin@gmail.com"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"69b3668427496e5b5d1ee00584aff2931ac29843","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.3.0.tgz","fileCount":57,"integrity":"sha512-NYXEgo2xrQkBIQsFjtHwKgbt9RZO5UYsyj8jlv1delLIQ0ZAd5ZjqWms9jGaMblwwXJaru0PTwna2zaR7VkJaQ==","signatures":[{"sig":"MEUCIQCgzVKnDDArlnpMK0QjP2O80nwXKJ3kjsXaASZbA1YMsAIgUjSofrEecGd2AWh/sNR8Bh2WoTUcJHwofGrhvLLo+Ho=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81454,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJifDrJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo4lQ/9HlrEqudVbO1eBCYpjmvFSHq2oaqel+83wyF8YShauq0g8Kkg\r\n5Ra0rNKrBwuXgsNBZHw4vHgTn5gyn3V0QjzscZX4Hsae6C3n1AgfR8GfwG53\r\nHwEmpSya63KtQjrCrdSkz4xIfnEjrOJrpRKyzGTtwmVwpX7uyW1IVMNtNU+U\r\nKS0rbGh+JAiP7lI4Zt9pG5Nw2sSZk6q2QaGknPaABAwSMVUu0f3WOrOQEjPK\r\nNaonHqG7hVZxyW6r716Cf6LbR7o/KB5jrjOG9eRbOIvGy1OiukoZ/2byIZ3p\r\nC4IZbEV6RKwjk0cWAEkI9BqjVQsHns5Pdrk3F8WdYLaPwRb//DwoI/EHCOB7\r\nGI7Y9xo6B9gF81kJY/wD3f1iCvqSXVP3d+s6jJVAJkZHr7c1qZ1zV2b7VUFA\r\nQIpePVjrPc5fqenwoIQO5faPCov/exhaBtsUZMgv6cuP3tq3d2ej2n7aomXV\r\nZEu15cy9jz1iNYt4yPEkqOrVOQd7igP3ZHUk+/mNKsMIdobIas8Dh6b4JnAi\r\npScaDgZllSCt7q/7/6eq/cWRgKDK30NuPOTm3mDxpJ0+NGua/0/DU6RlICcO\r\n3tZvFb8fNsJxWWw7wjSHDKErT9ORWEr12nEK7DyVpHS2+6j8XEf7+lk7wKxM\r\njsq8roiFfwfM0ZYIFvxELmsEIKwoFie0B9Y=\r\n=44xV\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"277a7dfe57c37f1c70c8f21d2f2e65848c2cd5a6","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.5.5","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.3.0_1652308681375_0.6625830417174181","host":"s3://npm-registry-packages"}},"0.4.0-alpha.2":{"name":"@globalid/issuer-toolkit","version":"0.4.0-alpha.2","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.0-alpha.2","maintainers":[{"name":"sergiy_chered","email":"sergiy.cherednychenko@global.id"},{"name":"danijelm","email":"danijel.mestnik@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"yrkan","email":"yuri.kan@global.id"},{"name":"yuri_global_id","email":"yurii.yefymovych@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"ufuksak","email":"ufuk.sakar@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"bojanbass","email":"bojanbass@gmail.com"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nbalaian","email":"nadiia.balaian@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"dmytro.andrieiev","email":"dmytro.andrieiev@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"mike_bazhenov","email":"imike.rus@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"gstamac","email":"gregor.stamac@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"majst3r","email":"matej.ajster@gmail.com"},{"name":"jan_gulic","email":"jan@global.id"},{"name":"simon_kmetic","email":"simon@global.id"},{"name":"saso_cvitkovic","email":"saso@global.id"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"vidp","email":"vid.pleterski@gmail.com"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"serhii.kolesnyk","email":"serhii@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"a_gorkic","email":"anej.gorkic@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"jonnathan.globalid","email":"jonnathan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"boris_keleman","email":"boris@global.id"},{"name":"r_hribar","email":"rok.hribar@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"47311fcc1ef523f5c8d47c8633255978119a3072","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.0-alpha.2.tgz","fileCount":57,"integrity":"sha512-W53s6IUrLajNOx6USnDei60/CALVczlksywYK7RI5Lv4j7SMoLnKSAClcsOIwQ3M2EevZ1cjQxE3grfR30TLbA==","signatures":[{"sig":"MEUCIAXh8dmXS5YjfZ7O+Mbp3UmOEY6cqyJ4n4p8BuHIwm6IAiEA4PgWjb8MkH5/7jYIYgBwIohvlPPcWFZR9vo+EoVpMiE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJijPe3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqw7g//WgZIy38vaOLjnqh7TUrP8OZXFKKspqamSi6jqNs/+fuRnjya\r\nzG+4Q/ITDYy0xyuw6HiOqdPD39VI8ZGgd+lrXx42Kk9DzoL3RjktIETMKNOn\r\ndZsiYeV+te6X8sPYMNzY9/hyhoGznY2keDqmY0iuf5kArWiXa5JsnStgy2C4\r\n68LIfreC7JU3VjHPpXouRMgDwALJiYXAXFrtibxRoOhAT8EYbGoYLgJKkq23\r\nC2+aRIuThsBml5Yfd4l2s/LtOj5FsEBXDm2i7s/cnSn36kWvDzZjYM2E5bnl\r\nMay0x7TsRe7IOTD1Gc8UYgF33h1KNqlKXC2GrX65uJQn6gf6SCRjaO5NYQxQ\r\nueauxvpcO6KJOcZluy6wvWL9hcvn0N2gOOqJb3qrpsdkRWg5Dqyujb+/HpZi\r\nUBiwXQmCTDE6wG26uYj03mLtoiIqPS8syHSHSUVOp0cu8ws1RyATkay35X3f\r\nOhcbGLw50dp8CZBhUUOdyh0i1NJq3Vdmie0YhiE3PTXMwb2s7o6pvHUThPca\r\nlCyGchGeAF1ls+7E+2LZiJt5RBs0lfoERzdl9+919GKH2MJwPuDpXDP02QOV\r\nRNc1JBSErZ3Vwq1Gk8ecOynsMvAZeEs3EwtbCvcsMgdSt8PuLx0HnM0Q2yJR\r\nNlsu/JvSmM0WMbOj8cljkOf4/27Ni/7AY1A=\r\n=QzCh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"06a65ace043b4515a98196dc52be38ce9d78d458","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.5.5","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.0-alpha.2_1653405622894_0.45304850838786237","host":"s3://npm-registry-packages"}},"0.4.0-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.4.0-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.0-alpha.3","maintainers":[{"name":"sergiy_chered","email":"sergiy.cherednychenko@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"yrkan","email":"yuri.kan@global.id"},{"name":"yuri_global_id","email":"yurii.yefymovych@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nairiabgaryan","email":"nairi@global.id"},{"name":"brankop","email":"branko.princic@global.id"},{"name":"edcalderin","email":"erick@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"rosicluka","email":"rosic.luka@global.id"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"zan_ostroznik","email":"zan@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"hamad4","email":"hamad@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"vojkor","email":"vojko@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"3af2980e0a1f40e6f77f5247cd94bbb2c51a0a3a","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.0-alpha.3.tgz","fileCount":57,"integrity":"sha512-ilwZsN0KKsYdastJZfzo0FE8bcYti0kcC6snztIEoJ7pkUwOBK7OHeEsf96ar+l8zWCRV9nbeffOmpTTzNEz0Q==","signatures":[{"sig":"MEUCIQD+sNxP5/M7FfnDO3BSMyzL571PbdvJkED0qE4mekO29wIgR3z3iKPa+ql+pNheBYodtY5xhauH+4a4oZ/kW8+hdHY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikORuACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpqpg//a+S/LP4+G8HlDsR9e76hVwyOioyQ3KYuaROC/JFO/L93MFLg\r\n9Dl23bAzWZBq8aIzzLYWxIA0g4bL0x9KM1KJ3ShFlEZgOgj7VhEHrmmdmzVB\r\ndbSjgKOPtfHJFLl47yx2T4Ggnz9qjSOQ9LXK3T+sH/P2vy3sdVuwFIFRtOeM\r\n8e7oIXpRfKpL3ApqGPcnAVvj1pbzxkzwPAyPYTi4l2Ud8/iGGht5Uu6ZXDXO\r\nxXk9zAuCWc1L7fW5fMtYUGPiHa1MW54hLX4e+nhGrCNlohU/rb7VBzALed96\r\nUu165WzPqsU4UJRIMikr7E62/IlQIn+eCfIVbWc2colfxuUCRrYshsUWmRt6\r\n8eZVMFc0V7eTPABh7sqLgV1rZgJxRPfmLwN8CNBrWyPNATWXJdW92bi7aiS2\r\nsAw4cYDVHc2cGoAFk/PNQpxU5TptdqmuiQrAU/2ryJ7qsu+K/hPChVvVKqr3\r\nn4gS9qR0if2UrovWcp20lW6zZTADzmltUlxg0N3tySEKvGIjfgPWue/orUWC\r\nnZR/We+YXOV3Po9NFznIenaM8deMLqfRvumTGeQnwm61GlM2DbgVT9A5Ryeb\r\nwdQHdCuqP2DVwZQAqh1+QyCglQq7UocATzVEDtW4uzmBrA/8Joz/2fnWQPC9\r\nntXDOOsbqRSZyWlLwnp8hFiN32UFkB5KtKk=\r\n=CDRX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"3b784228f4cdac4ff3985e15bad8fce0495625bc","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.5.5","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.0-alpha.3_1653662830607_0.983355276876094","host":"s3://npm-registry-packages"}},"0.4.0":{"name":"@globalid/issuer-toolkit","version":"0.4.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.0","maintainers":[{"name":"sergiy_chered","email":"sergiy.cherednychenko@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"a205a795a6bb68cda77d96d2c6ca527d08da922a","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.0.tgz","fileCount":57,"integrity":"sha512-rKoPb4w6t6Jut5PM86Hca/ID6Dlx738Us87z6LyPjbV0HTcjHyjN0khL+Mq/nrdFDY5mdybTvSQ1Hkin+eNxWw==","signatures":[{"sig":"MEUCIAsYa3BtwDoQ2Yc3UtMd1yyHNrb4dLsPcWQj5zGIyosxAiEA89XG+0MEg0/cuKXD9kkX/i5xDNdGLQc9A9fLtX5JkNw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81630,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJil3uiACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoqVw/+MOVpzNlDvyIfcVAbxI3vDYzG5C9YktuPrZpLD5Evyuy5SlZi\r\nSORYPWklVb6DAF8aLTCQHm2Fi7nhuh+8DfilvwKHxwUkE1djKaUojE/f3kRW\r\n8AWqliaXy3mvYhJNRvxIo8JtbVRRqc9z0LI/+x1501BQlg96epc6LazHEt4d\r\nBDZWYdr95PymRVR7E6Ctg/W7uGa7wRTOFgCoz9zMTN5PD5P3CKjkQsWC/0mf\r\nBe9nTUqkN+2uLQmd+NJDKuMFyvNlGmKMII83Xb2iY5hfUXxSqP9JuISEqdob\r\n60a4NgQ8TwNDjJiE747bMFW4vVVF1gFRahmZpgnz5y4gAtBOTKkyM2EdMRYP\r\nh/B73flPHx1+QIw/xLjJOgIVoakfJMh1AYakOV2/EOp0HTuIvrPRCLJ1sE+O\r\ntMC/8aicFwrtqX/IoTzCJfZy2cpkwfUgb9VmSnYVfdeIvTEK1xvjE1r2Cx+g\r\ngZtqd4i8IuaRs2MRaV5gD9dysLThXCH6iIN0MF8F5mnAhWFJrccvZyN5cH3+\r\n7BQ9JqAtxn+g6CxvRb0Oasp3QqQIcFRbFqw8TT41kK8yHxrkRErZMwGWFmA7\r\nFVS54UDwmXc6N1S21MMGyDJkvLLSfVZQliI+XfS2p0O5i5+5ig/DDD6x+iir\r\nAfzrVOTIG8PqcvtY45cvWck6N4xW9xrDE4o=\r\n=46pv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"0e19531a7488f8fc13393e774afe471c93f31602","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.5.5","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.0_1654094754014_0.5548587138619621","host":"s3://npm-registry-packages"}},"0.4.1-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.4.1-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.1-alpha.3","maintainers":[{"name":"sergiy_chered","email":"sergiy.cherednychenko@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"bfa60b29cf18f348c0029d4920cd8cd4c734e45d","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.1-alpha.3.tgz","fileCount":57,"integrity":"sha512-9jonAGz8bh2ecHOmTPP5bNIPb/f3Ksx3gzcYP8yHRV0RK/bJIKflNayF3CIjH26jN49IREtEt57CBP4ws2WIyA==","signatures":[{"sig":"MEUCIEv0yqRAeRt7e1eSKqAm2vBbMe871+gsak2BxGjXXW1fAiEAqhgb8ejMxPQZSlly65PTEHk3Dxg+Ops/Pzc/xz//FIw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":84465,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimlD7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqrnw//b2bvoJubAl9JCtzQPlO7eSw+N0UFLSuskFUXwOONE2tBBkaH\r\n+4hSq4aofhUj+0oiVtfKD4ju6G8EGYPtKycYLa1WcqCRXhjaFjq+oepdL2PF\r\n4h0GaIjgzkzXTkq7NVOJ1UE+TKZK9PMOk75rvVwA9bCuuCMRUvoZEZfr0vVs\r\n93i/yQa3vT0lhoSb5YSZDoZ9EBR5Ie2fwolKRwBNwc0JkxOyXNMEqHtZu2lS\r\ng7rhI6qvJ/iO1IcvuzAc+cXIJNS9SxO9Dd/iZ0sOCRSPXfcgjjYNyRLKWidv\r\njekdC4sdytltzj115Vv2zMDEQ2/3xWjU90PLzxKkTSrTl0Jb6UkpkkKS1eQu\r\nAQGZ/x3vJ4za1gKMBdWtKRvJo0wl34i7kxX3KJuuDZ4UfnBaUIV/EuJI+NW9\r\nbJJUaCtBNnJ+VfeTd+DLIs0Xx42GpOrwN3nV7FftkyocXVSCcUtXG62BxLGd\r\n4OQKK/e+H5Nbk3g633rfW2H340nqGGPvNBMnQqqAXZXXriGIzEWpmAYQZ7Gu\r\nPlE3CU5HCDctbpE4TCphzq1VtGb1Xz9cLs/IzXAEtNW0hno84azPWrQlitoE\r\nB76CPYUjFNZ4wdPc+lMrNfaMzbIVWF6mGTn4aOSh9DHnajAVUajkC9q+r43/\r\nqktjL8auf7m0+OnCbamzYAmpHPfAQ+6f5qw=\r\n=lSwm\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"393c966559c6e759ca2e2678867ff7e2e35ff290","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.5.5","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.1-alpha.3_1654280442768_0.16513567298648923","host":"s3://npm-registry-packages"}},"0.4.1-alpha.6":{"name":"@globalid/issuer-toolkit","version":"0.4.1-alpha.6","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.1-alpha.6","maintainers":[{"name":"sergiy_chered","email":"sergiy.cherednychenko@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"e4ae8da917f183c8f95b6d7ebc496c3b426e1447","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.1-alpha.6.tgz","fileCount":57,"integrity":"sha512-9UfVuoGt7D2nh0CFjXT/Z6RZsY9V6u+jQZHbcpiDjaiTvP4WpcikYkScpcyhQ4T3y9gl3W2d1W5GYFA112BIwQ==","signatures":[{"sig":"MEQCIFEDbm6bZRIqt4OShIHT50bk6GQAPJNmARtBqxerqA/NAiA3R4hRlPLL3RXbWRgwmaX9G5LE+QIwWNc5rqA1H4z0Aw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":84415,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJivHTcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqSbg//ZZjUnBSsgiLLn/OQc68fhjOukm+oakILrvuN5ZH7zN6avCbt\r\nqqFiDc77UGwA7qtChMNXrB8At2HZEjiupotfbpQu8P8Hv+dzZIxfzPL35Ke3\r\n1FGSUyuB9GguFDIM1XOQl0V7cJcpsnk4r/E0tqR3LV99ruv4WhaOdVjO4aPy\r\n20x2xnxEH6xczXNITwd+94lKO2lWYK3jkJALX+hGAsalwOyd02lr5LwJEHtD\r\nBnCBUDiVz6Ag+zG/ZtbYQ5djg5ZRo7Woa6UwvOj0lH5WtjWQmkz8b1gqcenJ\r\n+VGt1epGxxjEccCgzb7NDkmhi/NmwlRkhpPDBcxtaORZ5GWxfaqpVH5ggOgs\r\nft8iCyADo1jbb/1gQGZ9z2CkPALFBGKVV962aCDaQd55kJpewuon+6C8+4yy\r\nUbl+yzCjjj+Ob2pGEAmWtBVtwUT8VgCegkl0OWl8J2QPz7pCwGJqc55GpKJ3\r\nbm1KwMBum5+HpS8ecb4Vo89hZN/qcTw1v9fbJgLOZCuH3OxmumrVGH0DmZnp\r\ni7H/H2/6i/RqPpOOypJYYx5UhD8oknQ5X1/Ljx1cA9ly8rNDrC3m8oJwxB2k\r\n8drbPk36L/PLwNjDootbUTncYB4GhL0ENZlszbAXehzWHP786QNsAydwUFro\r\n5YS9m6tSRygOWYw0sr2ItRGS9G5geVBEK0g=\r\n=LT5k\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"3f2f30fa63516c1905388e9a3651dd8448941f39","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.11.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.1","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.1-alpha.6_1656517852249_0.2406690137714289","host":"s3://npm-registry-packages"}},"0.4.1-alpha.7":{"name":"@globalid/issuer-toolkit","version":"0.4.1-alpha.7","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.1-alpha.7","maintainers":[{"name":"sergiy_chered","email":"sergiy.cherednychenko@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"mkotnik","email":"mitja.kotnik@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"eafxl_svitla","email":"roman.tkachenko@global.id"},{"name":"articice_globalid","email":"artem.pylypchuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"andrejm","email":"andrej.markovcic@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cudr12","email":"andraz.cuderman@globalid.net"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"novaka","email":"andrej.novak@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"grega.jelenc","email":"grega.jelenc@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"coticj","email":"jure@global.id"},{"name":"anze-k","email":"anze@kozak.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"dejsenlitro","email":"arin057@gmail.com"},{"name":"dejan_global","email":"dejan@global.id"},{"name":"jf89gb","email":"javier.fonseca@globant.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"adamglobalid","email":"adam@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"gorankodrun","email":"goran@global.id"},{"name":"mmolinap","email":"manuel@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"lisandrova","email":"lisandro@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"524b420cb6d98798ba24fca0e914b8ec061f7f43","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.1-alpha.7.tgz","fileCount":57,"integrity":"sha512-uRt+nGk9AEfva06F2IMZpiNgh4FsZQKhFA9GkPUvRxUYdqVpwerEvmWsFw7bxzjqKXzs7A9QGAvUrao8L4c0uw==","signatures":[{"sig":"MEUCICshOBCsyy2Wbw6sLy0KFen7NeL899rHCqhopPfPJsJxAiEAndeEeqmFg6YWNKw/B9IWG8b69GXjuec4XtkTZOuudmA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":84788,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJivf5sACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqO/g/+JxY64jR9ITvZdKe65tp/0DsCZR5hwCHINlazKAf+tPYFEeOt\r\nydUukTGyiW3z/UrHsOmyRXarIQJysFhQiCeqCYsKkAOjgbofliSTpz71GGvt\r\nRBVi6PkBLwufxd/dgbL3TAxEkjgEjYNyYEPaDDPm0QFnDgsX8/LxM3lvY5rR\r\nqP9vA1llVh02iravh8AGskZ1SOVsClMe3HHu4FJPsX56jpxoPNLGqLZQSwKu\r\nyZBD0aCL4Mg+tSD1cK50z6D0vzJawBjKVN9jCfwfd3aWqMo+hf7e4LkL/Qce\r\nubRE/HETh3ToFbisQ+6Gbaa0HIojj8yKq6ZGW67phflgtIKNvr8kZ7Z6e6M5\r\nLpn6Gc2IvHNl2xSrdwzBn2AO7mqTlgxaftX2FqvSq6hyhhA5tb3d7c4Z7pID\r\nYd8/2L/oaDUBTCv97gHblcyEndxbkfdkZ7txLIJ1zV6bGtgxnfJaD7XGOCl/\r\nTal5JvPOkMtMYb9LKcOd1HhpAQTNECPlLYHt2KdgPNPKejqbEtZIdCdx/hn0\r\nwoBo5mCJyo3f3u0yd6cb6i97ACKjR7hDFuqXZsW1mfGFVfzJOK5DUgBvIRN0\r\nCVvgwl1W1Th6rgttik2hML4HpU4GnXDCx5N08JYM/dnUzmMywyrFsNi0rHG4\r\nX1zAKoK2fCgDKUMIYhCU73Tmv2cvZVdR4JA=\r\n=YwHX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"4f9da2d6d4801e4e33ff18d7cdaed9adcd9e644e","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.11.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.15.1","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.1-alpha.7_1656618604577_0.558719784901565","host":"s3://npm-registry-packages"}},"0.4.1-alpha.8":{"name":"@globalid/issuer-toolkit","version":"0.4.1-alpha.8","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.1-alpha.8","maintainers":[{"name":"henrykrychlik","email":"henryk@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"dodosan","email":"darjan@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"viljem","email":"vili.skornik@gmail.com"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"e68282ff2fb66d101d5aa121a8135fe20fb5f40c","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.1-alpha.8.tgz","fileCount":57,"integrity":"sha512-IMxhiniGch38RjRy8TTqA2jCl9s59ibnfJf5pnRPEFLrhuiYmsVP/8VyqvrFuyLHbC9vjBkytZNHzS4ds24IQA==","signatures":[{"sig":"MEQCIERurnqnWtQXiPaZ6wa9l3yNUbgV2OAKK7NxFJi9Gc6dAiBnuivQjf2nPDHcS3ZUOwKtiEPahQmF0rfHPUaJj7Wj1Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81931,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjBPFxACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoZOg//fFIL8UVmoulQC70edlFAj4W+6CkvQE+O6HSoTJsvlTouQ1LI\r\nMr1lAiGvu6JWJMZ3YO0A77dssVKCdR5Xsh7M7Jw2+x3CUtrDQd0/hJdtvULz\r\nJXt1lSMm9gZUKny+k5KJ3sES5B3SUf0Z5drHMcTKHFLx96CAG/uMWBFDxkF3\r\nMDMX8/gQWHLQXmUcT1FToIKz6WVwC9xKM1mGCjHBxMQmQ0s0do98ZTete6AG\r\noyk1fCajR7Cu1dnOal6LCcdEyQZl3AzpgrOemSk2n+TEy3omAmMCa8uWk/Eh\r\n3GdB+zdVR0cEhDYhmWcvsrEiVoNKuil2LwjElGhYdcM2y70+ngyLyAwupnMM\r\nbZeVLZ+I1dN5PuYBx4IoAMjDpTZdfY9AK/x0z8DgQqgo827VK4KrbRu1dHmW\r\nWj+fRyDxInM8hwU18EUxCilgW9R3+eFkfllhMubKrlh/M3HU+hdJXfsQYFly\r\nuekBejtWQXAnuBp0KOs2xprizyyBq53q50OSTRFaUcsuad8K8k1hfANsUMl/\r\n+xOK7h2+36FgQB99C3rAvsSyS9dW72MjFJUo9zZjp9dZjPPT1jG6+Z7gZhOP\r\nYjSGF+eqS8v+tXTc0N8zZKI1pPyXqUp6tvx1EiXqFSqWad+HHJdRT5HHLHIq\r\niYODvTfhnPH5M2rF0EFa5mb+I/T0CqgXSDA=\r\n=+ydi\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"a8af9da2252388d97e8a6a6c7ca550b28ab60139","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.11.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.16.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.1-alpha.8_1661268336949_0.5443031467428661","host":"s3://npm-registry-packages"}},"0.4.2-alpha.1":{"name":"@globalid/issuer-toolkit","version":"0.4.2-alpha.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.2-alpha.1","maintainers":[{"name":"henrykrychlik","email":"henryk@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"b1d10751e98008eb53a3de9b7185489886d89bf6","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.2-alpha.1.tgz","fileCount":57,"integrity":"sha512-xtPlnv8Kp/JlZW488Rrob5ACAUJiiLlp8WXl0F5fFWsw8DZzTPR8c+P9HfWz78saeGvzoKR7XhGhtikPaXXK2Q==","signatures":[{"sig":"MEYCIQDoqII//hXJsgBqCtwdd0DAR917UOYJD+qOP/h6vUvDdQIhAPnWE4q5ReydeTRLN2TVTV569QDJ/w6Yvy/CSLtG2Dvh","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":82020,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjD1WnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqArQ//R7dtffp4o23DKWhjUXmgSVzvA58AKcvHEhJpI0yRR/x0wYrF\r\n3n3yiH8YUwgCtlph1IBEkye3oUaFSeeEkfIYMpRHqIgg1S80oNVbLOfYSx4n\r\nJLMDwPe2dlXuvy+6zQA61g1vPLuS7xQVEq9KgbOfmo4OE/sDaEGKA8kxr9qR\r\n0OW7U7uD73w+VS4JPOxVO8uDywBHZq+4xvDHx4jqDy+nT88GcZBH1MA7mmzJ\r\n85a/sQ4DA0Oj2OEpJtsR37mvmHMQ4KcPcqFBUj8/qtD2904x8Ax93OUBWMnf\r\nZ8qADGrsESEApc6I/TFhyPtqicTZ1QtuRiZyfK+EKisXkkvEmD7DcKEXQx9+\r\nYegFOGcuIdUaHCX74JSyChI+NTNzAucXiilerDmdXR1Tslgtead5Rbsl+vJe\r\nW5QT8wrTONpx2kXK92jX0e7osiPxgHKoX/vej5SoQslm0Gy6xk+6iyiuCqwo\r\noXNod3aj9ADKaqRvJMmg5Vg4cjijFo3r8IOicLEWjpnOCf5zEoj106tYVLo7\r\nGhxukKiVMx6wCxcX1L4KhnrHfGEazGn1GmRflVeQSadr9XeJKVEbHyEdamzS\r\n5Md+WJZtgxhjCFYcnMJEg/TyZ8xO9bJJDNdoC/xidRZxkF5cZ2sm+wNbKvgU\r\n/yEBnvyAiQ3IDcfwHQxlVlzw66voW+y6eo8=\r\n=PrZh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"fde47e348aa639a02865db92aafce1d126a5eb8a","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.15.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.17.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.2-alpha.1_1661949350824_0.3384114326618366","host":"s3://npm-registry-packages"}},"0.4.1":{"name":"@globalid/issuer-toolkit","version":"0.4.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.4.1","maintainers":[{"name":"henrykrychlik","email":"henryk@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"robiso","email":"robert.isoski@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"bradleystell","email":"brad@global.id"},{"name":"jessev123","email":"jessev@global.id"},{"name":"robertgid","email":"robert@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"tommanuelgid","email":"tom@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"jklancic","email":"jernej.klancic@gmail.com"},{"name":"alexis-falquier","email":"endrefalquier@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"azakhozhyi","email":"artem@global.id"},{"name":"toddjcollins","email":"todd@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"rokp","email":"rok@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"},{"name":"bassgeta","email":"kerry@global.id"},{"name":"zmitja","email":"mitja.zabukovec@global.id"},{"name":"dillredd","email":"dillon@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"b5e73e30ec558af0bdb92e9b79ac590aff9dac3a","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.4.1.tgz","fileCount":57,"integrity":"sha512-OsH5OmicxpwXnl5/JkFF9h+Xtam593BCDQnEgBerOcO6dWlpds9H2POwV8Jr44JbBxsRoqurKG+JH1vDbWVk6A==","signatures":[{"sig":"MEUCICTUj6T8xgw1pLFZvwqphM1Ulh8mj/CyZ3Mn4p3u5FS8AiEAvuKkhwURh+3g+dDGMzHzPO812o9CeGQvY6u5/Ytmu6o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81996,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjFcGoACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrWBhAAnTi+pRCD9lD/rdIqs6AoJ5pYv1ARH9lSPYywFdAl0Xd4ye0O\r\n7y0370bUynjPGbgn6Rg8HHvyox33b11JP46myHL0KayLLNE1RT+cTxzrOtjH\r\n0vSeIkVAF8Z1aE7SyC4c8xXZEIh/ndunDJIgr5TCcSBtSys90R9LyvA49Yoq\r\n85wUXbjDExNX4vw8wzbbCJ2095E+2tkkz288Ky8HD4seYwUB6r9Tqh8os+aG\r\nLcit81B44JpFzUVxkZ2UbD8EsQrR6qRbeWjGvUcn9sogVo7Zn5xmyPcY3u5u\r\nJKTIMI87yTZLDjtI9rxYLeW1lEG0o3S8Sb6guptYLZGsWCvs2oJrIHozipzJ\r\n2igFwTxeVluPfjJXD0LbZeiB4tpVzAzzaFXf2nCEpFBnQFXjDRUaWJ6boqyl\r\nnUN074S214itbajQf5fVplFyTIgkfEbFlHiHtauDrZzM4WXGIbZ9G0cVAwGQ\r\nQwui8U7I6D1Ee35GkSwTYol9OffLt8nQRwAPWRIUudIRGQ3koH0N0vkEoEEr\r\nKPcBSPVoufqBnm5R/hhCmfnNgS64FhQFBQdanV2A642n3nR44Rm8GiXgUiJO\r\nYf/VlNnlZI5cmJCAo/XmHaZPd8Rx19L+1C3WOYPqfUPcNkG9209fLWw6EFhy\r\nytN/ZGJ0eECAY4nQ3uWzkiyvZ5qG1zaCtEI=\r\n=oerK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"527159fb0f41ffab1a78f489269ba2ba05d8d1b8","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.15.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.17.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.4.1_1662370215877_0.8049459840871818","host":"s3://npm-registry-packages"}},"0.5.0-alpha.1":{"name":"@globalid/issuer-toolkit","version":"0.5.0-alpha.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.5.0-alpha.1","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"7500fa448ff411481b2f9a5c36a5b6367fe27567","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.5.0-alpha.1.tgz","fileCount":57,"integrity":"sha512-wAtFVbn+hjTJQjrKSH2se1bk5aPhNKD+9ivTqIgrGDy6SVe1pBzco+iA0GKNW5/3T2sz2UHphatgw423/ooFAw==","signatures":[{"sig":"MEUCIHE5bY0OfycYk37xj/Tu5evaeD1tmXJ9X2aHRnC7FgFiAiEAphwHAdKGE6EBR5HQSgptEQpOzw0pl0s3gTrkabLnLzM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":82247,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6irGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp1LA/8D0zVsTdjGyAlpD0pxDHFeD1YoxyUN5ZpVSHX63LGtRQmLLPB\r\n80Q3Y5mPcpclcn3BxKFTxsv0TcyYI9aKiPAc29TzyCu2jEaGkg2mbFQMxuUd\r\ntgvA7umxU1ADdfnZWR66TZQG3+VcNYPuOAMIiXXW0DuXFMZXcPqski+7s/Ue\r\n06RveseDN5bqMA/DiTcDeTy2OmzlypqInKZj3AMYAR5zRXe+DH+9Y21J2xxQ\r\nJLjabsYV7fVJ8vclzKOCm1E3vObooO8ofji2pYOv/yUqXVhpvCRWrANnuOOt\r\nytnA3CeQTzwVTTU2eYzc9BF/zDPneaaOrOnt5U3RKJRokq6QvS96O1ZPuHpp\r\negV4ZwnYrjovM1O4/KQXSCsrpYmZ+Fqv5sRUudXMA3kc+E+4pBFn6ZEqXyHY\r\nEOPwxM/5uT+hly99mAVKHADB7RU5wHH48MD8mNvo7i4jBxQ7NGak55ZBV9E1\r\nZRqsLi6xb0VVOYjJLAdeuVmfQ5xC/0aYOLGDSMDvSWDc33XhaMvfIGKIkZGf\r\nKH7+qUMtIWF99tFgesYxY/LgcC+jgwOqso0sg43ZGc8SHJI90xxTGBBYo/i5\r\nUTrMzL2jpVesOHO3KW3TLPZqR8EyYKLkIbA3/ueJELVcOdwKR7/UVUBpN6rg\r\nNzn/i9fWbJdX8KGNjUZKTt0A8zFvBLExSWk=\r\n=9ccs\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"16bb4f482d3bc8c4a5e64bbb86e37fefafed557a","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.19.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.5.0-alpha.1_1676290757781_0.6504130112360473","host":"s3://npm-registry-packages"}},"0.5.0-alpha.2":{"name":"@globalid/issuer-toolkit","version":"0.5.0-alpha.2","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.5.0-alpha.2","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"dfdc9541fb5cac87ac461197fc047b3938da1df2","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.5.0-alpha.2.tgz","fileCount":57,"integrity":"sha512-afRU5RXN76xuzLa0GrGK2X2S2W0Ow4Y8zoVBCgzG4D4gBG+m2YQ/OyEE042kgeQutNXOwQzbyskAUch2YTzGLA==","signatures":[{"sig":"MEQCIE3xjuFNG6ha3FznuyTrlIsDlj0lFOmLnxuRzL6bM09QAiBJ0eqYF3aKMBy2lfFh4KLmlCOAqkXsl0iSenB37brccQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":82274,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6i6AACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoCrg/7BC1lWTUJAO9kePd3rHE3OoHSaUZCrdD1FgL/cYrL6mHav4PA\r\nuBzelEPg1A4luFWs0eL753nTvb7f4fQYmMmdWEaTDPOC1rOnW4B1WMRsWJUN\r\nzG3XQF4V237joeTLitWzEeOnrx3DDhI8twyDwAUhvHlGcwZhoFr93Q0EWJNt\r\nOQXsKl80/IkeY4gTC7y1dzIvoGwIFtfDzQyafr2xzRBAHm4A+j9X7PoMpWTW\r\nHQWTL79Mgh0n8s+zdNHuuH5LpX01RLccmwJVOS9C1pcZsYzKmEn+cJeuFEfk\r\nJpUUtIt/rw77gCm/CL7fFsNqpBBpXdaz4/tTIc+dU7QtdsZKpHlCrk9IGlfR\r\nCmB+jQp7ZuOHCFpcQR/ZFsip/ggeoNCksHC5T7GrIqfoJtfDAEp22Vd0bWmP\r\nQ4CTfz1xO+DEO4CBn8WsEHo/b07dW1yF187z/6xHchSOj/txI7L5+rxeelim\r\nEWwBBnwVfYJZ658Cc0Sx8MZatjwC4WLiny7JfB/tXI7jGbSlDGWxZ1lIIYVt\r\nD0YggzTGprNviQzyOprOM9Fs2OujGb+h1DAYSzespgBR9Hd+P4g5So7jYH7U\r\ncacEX6tAumn01T2KpziDpA49pfq18FrTPXxAzmNQyak4+sPkwldhtBJ4hVD8\r\ncA65VhQILZY/NMvQREwPWCvfhhqPszPWOWo=\r\n=zLVA\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"1ad1a7fd9b1685050df07f5db518a740de72a27a","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.19.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.5.0-alpha.2_1676291711825_0.8051848866376705","host":"s3://npm-registry-packages"}},"0.5.0-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.5.0-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.5.0-alpha.3","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"bcfc53e9a621623937f8afebd7e2099f85338ed8","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.5.0-alpha.3.tgz","fileCount":57,"integrity":"sha512-ZSgmAZz2lAFpOjFenD8b9BpUx550cYD8DViQC4z0DA7SD+vIPRtYNsRG3EbeWKHA8Nm5w1a9fs2Bjo0/tbpHBQ==","signatures":[{"sig":"MEUCIQDGfXNhDo4Ocv4WR9JTUmmd+/6HfU1QvMdQ9OhMVJwc5AIgOKUtGkPvLfHk+FV0FL9+FlivecufeX0DPUmT+Sdj1uU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":82306,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6kQaACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrwDA//eeDDsClI++Uopf1rTCHU6NZF+tOcjm9Z9HBpqsx6wmvIBqPZ\r\nREcfbJv3Jbhx9lq+4Bzkiqb680PO9757neCmPTxMeOcc0A6KlQAD7i8vwIyF\r\nYq0kDBNeVKHueUqinZvjsMxNy4E+/kjg5vmG/gkSp3eDsVTwWYd5ngAMjEOS\r\nxHVHLvWmweuJwT5Sgo2fdv6t2jH7ls4c04pUwb2wDEY6JiMpwq0Aemll9O1t\r\nan4eQshG4PjqU4vKxVOUZDS83tBN6EzPyXIEsBbqPZ3TlcKhRE7zlp3SaS6H\r\nVkBKYlX4cGsOFNzlJYdPot7lyGQs7VnuEXPQSpzPfR0Q7mrekCf3sI0dQdyf\r\nTJPV6gyKbgEjOzQkNT266s2nNSiPhQwW6C5Zmja1RsP1z/RUNp17/DNj7ww2\r\nuAwPxgvCF2h2bfWZ/M4mu0oEiKZXHkihe/50rFYa76yGh0nExeHrEPl7oPbO\r\nMM+lyswl1W9awPwZckJwUgcSaojee2xtUiRbw3iSz9Ges32zjgYTCu/9SVg0\r\n/hewOwEaJHa1YFRo/fJltwy3nONeiTGwWCLKKFAHu8sEyaZsx97N/PKR/7ec\r\nDYuNS6j8XLWykpu3MztQE4ovfCmMX3dIYuBNKUeYw6J2inbU44xHLXBJB3wy\r\n+KrV1ofJOzdYAyy937NxmKpZlRDua5GgPy8=\r\n=4EHb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"24919174344c8560dddbfeee754bcede6d596433","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.19.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.5.0-alpha.3_1676297241870_0.9313990252285782","host":"s3://npm-registry-packages"}},"0.5.0-alpha.5":{"name":"@globalid/issuer-toolkit","version":"0.5.0-alpha.5","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.5.0-alpha.5","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"7e964f5bdf04b3ed043986e38d56132b2877b907","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.5.0-alpha.5.tgz","fileCount":57,"integrity":"sha512-uWpgh4WxcYqTTitrOHsRtWb9JJdKaBS9zQja5sALVMgONcsHAOE9eDDVXvM1DVfxaHvG8ytjTWhC2mgkaXd09w==","signatures":[{"sig":"MEUCIQCMo5eE7IzRDklslau3IgnCPgxdqMqMSVf7QKxmW66YOwIgVLkOCaonUday2FYyo3t9o7pYFBuaE0xvakOZ8ZoKFO0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":82462,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj634pACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoMEQ/+LboZZgjGno+6ycB103M0HF423lUEtbM61KIVeKRG32ssmGeE\r\nQFmPswAH8IUnhCwgNYawqqU9lkRmzfJHxMW/I5C7Z4Ad39Go6nB8Rq4oQs7h\r\n0uQHmHuCiSYjFvif6EnBzuGAA15OrboNVsBSgLgzYwb/uFT8l2fiLoJE2DO9\r\ns3Qi2MN8bUDJU0+w33EKTIsNqetkJHuImc6EBRZ6RTND1gISQaUj+19aswDe\r\nd6Qj1pYiF4WYdjeMelApEVf+ySmrlLLqt4y2diiK0ONT26yHu9qWS8z1Hn85\r\nmWNDCr26+gC7McF+mqv0sJdGhTbjpHr7T0e+RW0ZDQGSjGZqpvJvM4DBqux4\r\nFJS97k0lLFf5A0i2iwMvU8H/VeqGc8Y9UWj64s+TqVowdmrADA3WzzIWRGDy\r\n31Cs+hMJt07be7gFzHx5XKTqpXvdzpZpFM2hJswxfx+yEa+Pse0X/xKRNu87\r\n64rGiOX5W/A3nvRLi8S4NgPKNvJJeq93NVDVOK4UUrV+ah5YCV7r0RlphNXl\r\nz2SLIFUXOFmpH9k3QX0SQflbigru1Lg5BO2IrIb56eYJAfFa6LBukAh1Ui6Y\r\nKpdfFU9748e/ru8tsu/L3KDdN75yTy0Relc3V6KKoq2+OdXy1vC+O74+G1jo\r\nnNFA78L4eHnX0Txq8NYeZT5ZZAmAE2eOZVQ=\r\n=MqWd\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"f894eef2d120138d833cc173989363c787a351d0","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.19.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.5.0-alpha.5_1676377641094_0.5996431658984798","host":"s3://npm-registry-packages"}},"0.5.0":{"name":"@globalid/issuer-toolkit","version":"0.5.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"ISC","_id":"@globalid/issuer-toolkit@0.5.0","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"pavlo_global_id","email":"pavlo@global.id"},{"name":"savvagen","email":"savva@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit#readme","bugs":{"url":"https://gitlab.com/globalid/credentials-issuer/issuer-toolkit/issues"},"dist":{"shasum":"85eca9ecf5b4a7b1707143f619ff4171f116c098","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.5.0.tgz","fileCount":57,"integrity":"sha512-iHs+z6iwJsUYhray86FKN9cZSah2i+PRin3uJ80gQTL3q3SEAUU7n/sldZS+kffurr5+73KdQ+VhiK9W8Uwyjw==","signatures":[{"sig":"MEUCIQDnWUqq0TvCOAVj0T9ocDZWKhGQPlVUw0jzeQ/H7AUvHwIgKxiKEZ9WA+1Lf2hmtD875lj542T/4XqtLYVGsV1xdvA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":82438,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj72HtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo80g/+KyJarWJDxWyv5HG+60Q7QUyK9AIRP6dbpXP7JorBd9DH/VBK\r\nB5i271Crj7S2bmC6MUmKKKbhEq5wZTyxDakXLzdWI6Hq+HQJL81hHCkoiUJn\r\nGVF6rLBFtcqwUj3L5uLJVH2D3sSUg46+m42JKXb3p8BvEAexRqeRzO7dCTLR\r\nZIs2ysG4HHXOE0vzJBAHvl4PKnyVTg04IsfcRa0UumVg60ShbZh7g6CB7XlR\r\nQpXLD+z4dkMDAvnlEIs7R/hE9lzKQPno3R8BTf8saKDF3rpXW2FUwAbAzmlJ\r\nzcIn7PHMheNk880xkPFjXenax2GyCQ1uX6rEOyKb+rzaswmVKUQjA4H/80mX\r\n5cvbfuFxeYk5mqxPIVD02oVdoQS1+dgxC+MLMUG8NUlM13K4UhzJSn9He6WW\r\nmayq9QS+yhLyLPYD8v9rEJNbVvMizu16Ggq5TN82KKbEbr4TotKXDq3sOoH1\r\nDCA9QgwzCtxqsWqYcbMFICa/IElcLBL/nXJQal6auXOa34/GThN3Cy5WWlNb\r\n32+N4ETGVoHEFTRHb86Ylx+1+bwIfZ3W5uGPwszWYkeAsQ8ShfLBYxa9Tt8v\r\nS0kGUSU6v3UwunAMIOHxzUO2eYkLwg7NDUMLt9r8zImGbgLsQPcL9b3INz40\r\n3wITeCDyGGIQi6h12SHvJlzi8nIqfpIE/Sw=\r\n=pUCL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"d47e95eaffa7adc8d784e9c2cf881e9aa749c300","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://gitlab.com/globalid/credentials-issuer/issuer-toolkit.git","type":"git"},"_npmVersion":"8.19.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.5.0","axios":"^0.24.0","dayjs":"^1.10.7","form-data":"^4.0.0","globalid-crypto-library":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.3.1","nock":"^13.2.1","sinon":"^12.0.1","eslint":"^8.1.0","rimraf":"^3.0.2","ts-jest":"^27.0.7","ts-node":"^10.4.0","prettier":"^2.4.1","genversion":"^3.0.2","typescript":"^4.4.4","@types/jest":"^27.0.2","@types/node":"^16.11.6","@types/sinon":"^10.0.6","@golevelup/ts-jest":"0.3.3","eslint-plugin-jest":"^25.2.3","eslint-config-prettier":"^8.3.0","@typescript-eslint/parser":"^5.3.0","@typescript-eslint/eslint-plugin":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.5.0_1676632557393_0.19130289013421575","host":"s3://npm-registry-packages"}},"0.6.0-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.6.0-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@0.6.0-alpha.3","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"fe7449456ed5ae6a4b0d64b9dd9dfc73e67d8e60","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.6.0-alpha.3.tgz","fileCount":58,"integrity":"sha512-tzzTm+bFgH/3p96q463sQnikiTDBmlv/PzEIjpPocIR5sa8z5+h4SIixmBihXCjVzmwSvDGy1oQQd3OP7mJJaw==","signatures":[{"sig":"MEQCIFBuq4aBSY9zIELHH6/IdipuBhJrRmVzHvo1sYODySxiAiBAinl6M1KAwLa0wsfAPvZ2ECoTbY2S/VvuENE5h0OJIA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":87240,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkJa60ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoUjg/+OvF+K8A+bZAykADRfzBH2/uaLvfP26TOMr5AcTiUS1DIPEkc\r\np9iSaHEQG14NSFMnds0Vdm8iLkHFnwwmaM6wdMKZRc3bzpGVfvCv11I/kDtJ\r\nWgYH721WYFsSSbZjADbMgcpA4yBwuEV823iuq4fRjV7zgosBKA3XTKR/CbQQ\r\nheFA3b4IvVe0deTlZ1y9ahrL3r2WfzBy8mwltbNXIngZteow1wePoTB40KOz\r\nDGCMGiXcJePXiRzX04mtHgNpGa/K1gALR0GgLfLet2k8AiJ+s6RtD5ld1GCI\r\nXKa/aq4jHwqNB6SZwK6TmYSzGtl9u17a+CKRmc1jdJ7poYcdG1zujfhPEDZB\r\nH7S3Hdi+vZzUxit/rFc9JHDhABvOuNFvDz592J1OJVnmBT/quEg5NPPYwuP4\r\n7JUdXgwI6vnyBgBCHsnBs5o/9mp5Xa/VOZS4SxsLYQcCERwKJbj7zP+4dZld\r\n5sxtaNDcP5UkaSKY2Y4tBtw+F3m4vIaN6u6NBy2YTQVWEGSUvkkv7HxSbZwO\r\nsayEbnJSYA355aKNsPWzRptk2e/bLGQP1GCl8JLUlPakSmFAZY/4PUn8ho37\r\ntLannHBatfGCSYcZkuaaZ+gOeGOfYeTKKYlouuOTtMi14L5JFviyKTdIViN/\r\nLrIHnn0Izv+ZcCZ2coqqV45YFcXbv2qpw84=\r\n=nyC8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"2a7db206ab33ff36cd9c69ace423a9aeef1874b3","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.15.0","dependencies":{"joi":"^17.8.3","axios":"^1.3.4","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.1.0-alpha.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.4.3","nock":"^13.3.0","sinon":"^15.0.1","eslint":"^8.34.0","rimraf":"^4.1.2","ts-jest":"^29.0.5","ts-node":"^10.9.1","prettier":"^2.8.4","genversion":"^3.1.1","typescript":"^4.9.5","@types/jest":"^29.4.0","@types/node":"^18.14.1","@types/sinon":"^10.0.13","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.6.0","@typescript-eslint/parser":"^5.53.0","@typescript-eslint/eslint-plugin":"^5.53.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.6.0-alpha.3_1680191156557_0.7751450600090932","host":"s3://npm-registry-packages"}},"0.6.0-alpha.5":{"name":"@globalid/issuer-toolkit","version":"0.6.0-alpha.5","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@0.6.0-alpha.5","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"fe60ada27ff805143671948ce9dce6f44522d1d8","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.6.0-alpha.5.tgz","fileCount":58,"integrity":"sha512-5O5jJescaVGTZ4FM8oD7qvlJKQ5sBjo4ugAhqMKEgNpvSkBcn39ItcUreBYTpX0gVC1sUAbUgEB0IdyqGx0e7A==","signatures":[{"sig":"MEUCIQDiuMOukyRIM6Xc9xhe4F+gALn6dD2/UlTwkE0Xtxu7KwIgD21JxyQ7qWyU2cP5gshHvN0HX1GU7om5rQQN6WjLZyY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":87252,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkKs27ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqewA/9FZ6Yv5gUHISo3e9g/JDnZ3AKM9u13xsMaZGKaUX+cJOe2ix1\r\nCUqP9z7O0vvXwThlkW7ZXv3E2svoDkXdB1iJ8DKeXGYnkUIYvcjJlFI7t7Bl\r\nRMntZJ5/M85CBlDQHwrInoN3gWFGWsvhSHOg/2RdNEPzE9evB69//b4hN7s4\r\nP9Y7bISDkg9fFVxZAO6DhI8ZkFqABTukdyGcusiqTxDIsUp1A68K+lJT6z3c\r\ns2a1cKQhY1yxMwuX0Od8YR21FrSF+0rOQjypEXORUmZKurHf8/EEjzSrAyAe\r\nMJHXgHWZzXWwH+fcJjW2n0IVXDIiX/IWnIsLvJZYOjw+A+o1Lx47By6k2471\r\nwSvXrcgedPklqXleq99RtH+j15fCoOV5tVTA3S4Ns3xYslYVC3ZZCaJN7jK3\r\nxvjyQuBSOkaVyVLp7tf/khUOPsYrdpi2dmI0+jVFE7QbY/+HW9aizB89Cvin\r\nHVnok7qVEAFQ7+QX7YbBsnJem0IKz1KEs2yuHUKnRw9NdKMKyyv33u/hw/8G\r\nFrqCpzP4GfNb6pcmM0AfNe4DYToybOB49oaXYScvupUPEqVHJ214rwe57BdG\r\nnyW08VYgdq7JIWObeNN+S1J6MX6uEJ95PfAnPF/QqzwLKNem/lPLVqT8KAxW\r\nfpyRk5JtmO7Cmvc7toajlZA8v/vwXzFiD1M=\r\n=xfRH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"821e9d22d7e66feb90ff020c771e7f0879c865d7","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.15.0","dependencies":{"joi":"^17.8.3","axios":"^1.3.4","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.1.0-alpha.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.4.3","nock":"^13.3.0","sinon":"^15.0.1","eslint":"^8.34.0","rimraf":"^4.1.2","ts-jest":"^29.0.5","ts-node":"^10.9.1","prettier":"^2.8.4","genversion":"^3.1.1","typescript":"^4.9.5","@types/jest":"^29.4.0","@types/node":"^18.14.1","@types/sinon":"^10.0.13","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.6.0","@typescript-eslint/parser":"^5.53.0","@typescript-eslint/eslint-plugin":"^5.53.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.6.0-alpha.5_1680526779155_0.21092091788925216","host":"s3://npm-registry-packages"}},"0.6.0":{"name":"@globalid/issuer-toolkit","version":"0.6.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@0.6.0","maintainers":[{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"nelit1","email":"tilen@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"458b93e7337f9c74fbc08a141cb5c1a057aaabad","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.6.0.tgz","fileCount":58,"integrity":"sha512-yLrEtWZVpK/90cK+38Eb7xq1PPIqa6r6JC0QfaZ2UFiDf4+fCxLry8dnjgBGteWuP3oXI2IYqFrFjW1usPIiqA==","signatures":[{"sig":"MEUCIQCkRYRh1Noa6/o1guHN9CJyu7UTk8/zRuCLVuK3xoCb5AIgeiBnPFKpQkxFQaGPo5/QxcjxUQfxVrKI04PFgpcow9M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":87220,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkLACdACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpuSw//Ql1iIyVQrln+8Y/WGJf5nAMJXKCvJgm2BWhsiJEncPorLDB6\r\nIf3knuYUS53o+DHz3LwzUixMPeTw+cepgrYqVa600KtxgmM+60zWC2dsx7lk\r\nKsJ8l5H55Qs4M4YJ+Hyl9Eaw0cfI/v7KZhxz7aqm2/X8pvC6e4jdw7jyQsGH\r\n05uvyDzgpNbaQuUz5VI6De/VaJMmPu9SNShWuUD5wMXmnfDKkdxbNs0QmuyT\r\n1h+Z71tBIo5yFfTvA1KsW/s2Kq8iCyEo4GBXJkWqogDQbYrJyWPJVYHaDocw\r\npl6oqVHyYECs0wSoLi1hw8EGZmBhcN9gXqkSyCdBA0aGVEYA9c6DUHjEx5R/\r\nnVp+jgxUfmCOstyShUXsjN+y6Vwk6+ACBcaOEZZQF8qyesYdXBtxuQ6dYxcM\r\ncJqO74LfnaHDjWcsWCuapIxm+0cZKoCTqa6dPylMIOAFT477Q76ZUBLNWrTZ\r\nHBZMW/5p5lpcpUyn2fDxYRi3yI1u2F1UesYEz9hXt5phSH8OY6UJnuBBv98Y\r\ncvXRv49tnl/0hmuGHInRtyOsm2k91x1qBS3hZ+TMa5kT9zubpns9gBGIrzUT\r\nWZos5W/aH+fhfw3v4aX+jf8pQORwmM2ZlQh/RMp7TBNcQ0fes1ZapHVoU/Vt\r\nAo2sfWt9RpkuAgKLiWOJi9jxm3ue6PXkUMI=\r\n=Wrc8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"14fed2372aa9455013fd741bae645208cb452f43","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"qloud.io","email":"accounts@qloud.io"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.15.0","dependencies":{"joi":"^17.8.3","axios":"^1.3.4","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.1.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.4.3","nock":"^13.3.0","sinon":"^15.0.1","eslint":"^8.34.0","rimraf":"^4.1.2","ts-jest":"^29.0.5","ts-node":"^10.9.1","prettier":"^2.8.4","genversion":"^3.1.1","typescript":"^4.9.5","@types/jest":"^29.4.0","@types/node":"^18.14.1","@types/sinon":"^10.0.13","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.6.0","@typescript-eslint/parser":"^5.53.0","@typescript-eslint/eslint-plugin":"^5.53.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.6.0_1680605341518_0.5537478871193122","host":"s3://npm-registry-packages"}},"0.6.1":{"name":"@globalid/issuer-toolkit","version":"0.6.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@0.6.1","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"8ffbcdf122de26c13448a50fdcf4f5313eb80112","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.6.1.tgz","fileCount":58,"integrity":"sha512-/++jHl7dEBNGK0fOeY1lWAMt2FjUIq5I7j824CjRNCh+5nnBGpUbNZIOy9oYDvsBObo+oQ6wUXOyDnMBO64pjw==","signatures":[{"sig":"MEQCIADZCoizHdWeSpfg/+n0dMLYdXi3sN5K4WTQeMJ8+/DnAiBtOX58wI3Xg9GKor4lBFFzInrgXnrJMDymyJbHB4jliA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":87221,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkQPcsACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrPWBAAho39XvscdauBXpZFR4+TpfWGru03+UdOcvTSkBQakEUhh1bK\r\nmtJEc/QyPxbJMdD74yatoYgXgWAISdN//5E8b0kmkAtb4PShYKa8mbiDjGmV\r\nh5u+G8d/GP0L+BaBBHtu7LeeEpWwbEFSQSYVbsuEo6A1OqYyLTo5trPFxt1h\r\n0xhhpr3uZuofVnA0UtLKpIjgL+Xnk63lwBbrWautkr0Iv438mOYynQ5SsQCT\r\nrPbjjCKdKeU5kOOhkHuPgiUS4zSj/V1IL/gGGXVlvCKSi0ZvLBMGErjkxa0/\r\ntcymnInI0bEUvH1OfZEYr5F7OOfdcz8kDayp2sF7niczGmDGkEjqVGfk7xeT\r\nHDL37bY0qw69gu0Z+2pjw5h7Czv4AQYEeOJ92fgNyxq7qFBTg4ndD9K4bFLn\r\neGwyNjrKQqAewN5lUC74u9Fd0rGfBLhoTl2D0DAWj3cpzKDEeO5oYvt5UF/H\r\nLPGfcegVPJOvvuO+NaACvHQ0jOd54NovZO+ge1Tlb+AesesTBp5BQxxcuAQc\r\nnYVoQ8RpnGur9dxrnKaHVg/md8Txn7097pGWK1Yqjje9EJqbermnWk5RjLtr\r\nfuVfsl3QHvHJdvnOYufzeFvjKgqSqUvk0+r4br8zemPJOzfEmC8XvJdCiFpS\r\nmN+AHb5FihGuJFfG125JXeV+JpWSmpiYxBM=\r\n=BCrf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"43f1e703533ea8cd7ac18d6c894367294e3c1f74","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.5.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.16.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.6.1_1681979180114_0.8162195287840719","host":"s3://npm-registry-packages"}},"0.6.2-alpha.3":{"name":"@globalid/issuer-toolkit","version":"0.6.2-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@0.6.2-alpha.3","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"14147c15fe05c3ac20ad6474281b158c30690ff4","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-0.6.2-alpha.3.tgz","fileCount":58,"integrity":"sha512-YZ+UMtOmNZ/2aK/27LGzvgVvRgsxx+IFMj3RSqCsN6L4h+xXUQ5phAt1MsqSfSX2+VwmzoqXb9Ctsa73fmaGkQ==","signatures":[{"sig":"MEQCIF/rhNEm3KSUE5QX+ni21XIz1pN8UMLHCeJ9+7shXbmFAiBRAkY0AhGhP74wKMnBVhAbZRGYuS6yoSQ78Qf02StEPw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":87996},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"622298662a4433830961b51ba6984e563023567d","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.5.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.16.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_0.6.2-alpha.3_1686649291581_0.13752653660857006","host":"s3://npm-registry-packages"}},"1.0.0":{"name":"@globalid/issuer-toolkit","version":"1.0.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.0.0","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"blazmrak","email":"blaz.mrak@global.id"},{"name":"prorok26","email":"vladyslav.raniuk@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"uros.smerdelj","email":"uros@kaldi.si"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"giussepr","email":"giussep@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"b8dc721295b4f6434aa5844eb2c5a15f6712b1f6","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.0.0.tgz","fileCount":58,"integrity":"sha512-x1KdyE4nZOV2sm1GNEFuZTw70kgESs/wxK8pk1vsOJlfpQccCSDrnGBzxyNNxZaBvYq9LrbroGeVl3DWlPU3nA==","signatures":[{"sig":"MEQCIDtIjKqnI7nL3Hlr9KDi0nqqSSpsRV+dDPTQG/8HnUpAAiAn+6CwPf4ZAQLlW//v1198zfUqE52VN2y8cNbBHaqMcQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":87972},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"9168de2fc85b4d785e2cc951c1e9f117b6ae0419","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.5.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.16.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.0.0_1686903607644_0.14819068568382932","host":"s3://npm-registry-packages"}},"1.1.0-alpha.4":{"name":"@globalid/issuer-toolkit","version":"1.1.0-alpha.4","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0-alpha.4","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"c4b3f4c429dc12a8ed9120bf2536987052918ae4","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0-alpha.4.tgz","fileCount":58,"integrity":"sha512-MZFsi5niMvXAd1NDBgByNqDQPDLweirv0izTt2kyJTaG9RUwerDC8RmWVnKfw5gpBnkeDYgVacH83EslVUQhRg==","signatures":[{"sig":"MEUCIDiIepWJ0VYkLCEi6tOhpcKnQoCCRt+CMwnnkDCFRmPlAiEAkF/xuLGwCPGqBk3elycO7F9QGzekELvarDSux01TQGo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":90022},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"df4aa0c000666c593317ce4b3175a867e9f2d5e6","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0-alpha.4_1691492287855_0.25082842221513935","host":"s3://npm-registry-packages"}},"1.1.0-alpha.5":{"name":"@globalid/issuer-toolkit","version":"1.1.0-alpha.5","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0-alpha.5","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"1aec548d1e6db34220666b5b3a648a08edfe92ff","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0-alpha.5.tgz","fileCount":58,"integrity":"sha512-xEUjFkWHftEmIHdI6ZDsJ3Q0oMad4J5PuutBYdAV9sT17KZq9gIlJBl6rDEJ4bj9Id2wnXvgphedYQfI66VzAA==","signatures":[{"sig":"MEUCIGuHsQmNAJD31X7Toz87p2ErEMF+T0R/tUftp9q6aGGTAiEA1GY17q8GPH0Lmx/LaakIOo9Ye8mhpiqq5KevOEF9IWM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":90125},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"3f6a720d874047a92d9203e3babcbad6943c464f","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0-alpha.5_1691497170117_0.14974904739291506","host":"s3://npm-registry-packages"}},"1.1.0-alpha.6":{"name":"@globalid/issuer-toolkit","version":"1.1.0-alpha.6","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0-alpha.6","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"bbce82dc1d290a6875e7a525f270962ce0a7b061","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0-alpha.6.tgz","fileCount":58,"integrity":"sha512-rzsN3CJWvKxd6znL/ETettdpOxvMYBVnSxAqgetr1b5PqDH3RsporgHvMtpI49AY49CJPpFR1OOPROUdn6vP0w==","signatures":[{"sig":"MEYCIQCAUKoPW03ZknoJNI0C1sA8uKhBH/c+umqSv3oM0AK60AIhAOecznHTWoJ39YFpp8+xQjn7HMGaWuNkXkvAmNV1Smuq","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":90183},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"cc6033eeba2abbe8f234a6e1bf64f3486667b209","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0-alpha.6_1691497387053_0.6372235008600222","host":"s3://npm-registry-packages"}},"1.1.0-alpha.7":{"name":"@globalid/issuer-toolkit","version":"1.1.0-alpha.7","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0-alpha.7","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"f366202402a9c9a0d695a5895de676c48eba59fe","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0-alpha.7.tgz","fileCount":58,"integrity":"sha512-bZsLUfsyVKYfc2GLj4TrQFzGfzlDzbTx/V8NAqsFPlJdvX4CSP6TonIhMOkIscQ+3NmJYxQX7U7EtHjskLJXKg==","signatures":[{"sig":"MEYCIQDpdDn0mVApOoxASYkGmUCXGPjFgnY1P6CVcY7U4ow3ngIhAPlMTHwTtOWXlYNwlpKKOJKH/GNrQghxkl82sJLjffQ/","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":90938},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"610519805e45bb9849788e399c9d29055b14ecb1","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0-alpha.7_1691497919718_0.292196300493768","host":"s3://npm-registry-packages"}},"1.1.0-alpha.8":{"name":"@globalid/issuer-toolkit","version":"1.1.0-alpha.8","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0-alpha.8","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"1da487be142caa602306b5f570604690ae858f6d","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0-alpha.8.tgz","fileCount":58,"integrity":"sha512-E5YVuxAl32dKgaXuOetrOMifS68S2jaR6fYjIeF1JPQZD5Q8QXy0G7Ghdli2elMILWA4mgZPD2IEsB9KbNn9lQ==","signatures":[{"sig":"MEYCIQD50N7STMZvBLS3CR4sIENXhrfUT6zs6SQUz988LKnuZAIhALP0Hu44rA9KlifJn2OXNX4W7oh+KgjosixEZyHqwwra","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":92635},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"e5965f0b5dcd97c6b92368c4417b9f2b77b385d5","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0-alpha.8_1691565093229_0.16478050200253858","host":"s3://npm-registry-packages"}},"1.1.0-alpha.9":{"name":"@globalid/issuer-toolkit","version":"1.1.0-alpha.9","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0-alpha.9","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"8d4fe9fa67678906be1e94a6cde183e2e9db3f92","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0-alpha.9.tgz","fileCount":58,"integrity":"sha512-aVpdwP4gkzDiFiK1ENSDO4Gd8oLkMuF8VIjW0u00N/xlAuVRzG9GBxdewZv58IdxOBNr20pR7OIh3iOl6HSZsg==","signatures":[{"sig":"MEUCIBgqun7nbCmHgMw75HFN1zPAyCXcOQ0LxhHOXqyDrXSsAiEAhNpWEkjwMLMBIhkHOY3Vnx8NewGNL7SuW+/Q/bygbFU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":92695},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"6b7fdf481db5a33171799c3c4f2c5b11dd6c6e00","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0-alpha.9_1691567938245_0.8184464351328467","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"@globalid/issuer-toolkit","version":"1.1.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.1.0","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"63cbe974e713bca05e3bb01925caedabc5255eb0","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.1.0.tgz","fileCount":58,"integrity":"sha512-7bwsjBdENgUHRcfGH4CsjL6n2g5p6FpQM9Xw3mhuahu942uFDD99EiUlviCUn6+RgpAYHFaFxxq2z7HYCf736w==","signatures":[{"sig":"MEYCIQCJqzOJUiLRr5rZRRoH0g31cUJVJ/J0b6EU1ucl8XvtCQIhAMAxBs/smGgU4Czzar8lFtUgEuDJFk/0KstvCZaRJL8r","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":92671},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"806fe4dfcdad54ea1b090be46710fcc0ac0f9138","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.1.0_1694417924542_0.45688375455370256","host":"s3://npm-registry-packages"}},"1.2.0-alpha.2":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.2","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.2","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"b9b53a5c7e16ed3fd2da1da6dcda30eed29c4139","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.2.tgz","fileCount":58,"integrity":"sha512-NCksc7U+LIWmOC6zEmFeuWhy5T1LY1zDUQ8ydiMJAw8ecM6oBEObzxI1wzLycd2AqF+60fz7wjvH//AUewV2pA==","signatures":[{"sig":"MEYCIQCp9N4grZXcUo4hsjkoDwiFLNU3YzoW2A+iusFhh1kJMAIhAN4NLpAmLo+CwEB4DnZmZAHJiOh8hg5u940IbCXjC/XI","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93227},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"a92b0c289566863acd65db9a581de7ecb1492f4e","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.2_1695726230540_0.5084232450059749","host":"s3://npm-registry-packages"}},"1.2.0-alpha.3":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.3","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.3","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"8acdad4c5d211b90eda65be1612d30998aae17ac","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.3.tgz","fileCount":58,"integrity":"sha512-k4eevgzd4weVd54NexKaQZIs+/4XUm3OwuTkC6FsEEruZrCMTLOtsgpLlLqRHCM+k6BzYuxx12e8GkBQmx39ZA==","signatures":[{"sig":"MEYCIQDshEKnxKqKHbdwC7HEYniG5q58v6x/qX7MFdf0VSNBugIhAIj4NQ1bOmKl872Dv/4mEOtLg0Bv2YLpDhKcztOV3XWR","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93106},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"5c0019d24536e716775fb8312618ab4b220c20c4","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.3_1695757015341_0.5368588114489656","host":"s3://npm-registry-packages"}},"1.2.0-alpha.4":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.4","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.4","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"2efc5a8a20a838628b57f87214e1fccb549821b5","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.4.tgz","fileCount":58,"integrity":"sha512-uPuzAxkAkOqalq7bmPQHog8lxVehGnlWsL1Q+2WIYtD5/744rJuj1q7XA4q6b4Ut3wRJP1Ea1eTVc7pzWUHfMw==","signatures":[{"sig":"MEUCIFqO1yR3tYzz/gIiVq5aXzGDPLVFC8HDf3mEDLroPZNVAiEA8zxE+R7atSDLU2udl/siLQffmggA9B+XBUw5NItLkEU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93266},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"f73409f70f591f7133149665d22687a87f887116","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.6.7","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.17.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.4_1695806507899_0.9046164982501932","host":"s3://npm-registry-packages"}},"1.2.0-alpha.5":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.5","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.5","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"8fe5db91ae8b3b248a6577482e88988025637ecd","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.5.tgz","fileCount":58,"integrity":"sha512-mTfz4v5AVgtj5gKPlTk5IVLGMyYFFrZyU+9bK8yiVXZLYDo1VId29wZBYKzlYBE9KdwvpQrqo0+hU32WLPHq7Q==","signatures":[{"sig":"MEUCIGKV9R74mHa0qcDI+sOI8g1MAH4fqtfZpCwS0WTDShd3AiEAg1xxNM6dZR1ks0BpljyeMNLUESgsl+OvQKZsrVkK0GM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93377},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"614f81ddf935a629d1b3b1ca14e30d11c8688748","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.8.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.18.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.5_1695809314086_0.10722203191578128","host":"s3://npm-registry-packages"}},"1.2.0-alpha.6":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.6","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.6","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"d80c4be7df362950731bacaccf425b0fbe878285","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.6.tgz","fileCount":58,"integrity":"sha512-+7WX/S2bx7Xd/ID8o976JdkzWwAxjVQBxnV7ehE7BTVWoy+T8hFFn5LN46jFZQzBVxZMqyAOYh53LM91Bl3QYw==","signatures":[{"sig":"MEUCIQCFf9bwTLjZ7g9sv6Ovh6DUeNhMzOpYKlevEuzxM4TDkwIgP4KqA60BaVF55b1mrb1gzs34D6PGCK1wjTMqWUz0XPM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93742},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"a30aea7eee6297d1aa39fb2242f360e6fa11b200","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.8.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.18.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.6_1695927281466_0.5147682415423556","host":"s3://npm-registry-packages"}},"1.2.0-alpha.7":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.7","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.7","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"dc02dfafde2396d3a6c5f540ab4f95b9eea35338","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.7.tgz","fileCount":58,"integrity":"sha512-9fR8hjc3BRv4RQTTgUXZa9+dAyzipAV+d6b9f7x4rYUVY5wMwacn7kCnQ1dk5HFsomGRkFgyfnDIo952ibLplg==","signatures":[{"sig":"MEUCIQDw7CydqUkYNuzRwkpqXHT/iAXpwfXo2shpqeyf9JaOugIgdev2N7CbVrtE4wFO4Eb/sU3NtrzXnGxGhzCk6hed8Ag=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":94318},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"ed70af8bb4d08783ed8fd80b836a63419600756d","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.8.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.18.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.7_1695928852201_0.546322782720251","host":"s3://npm-registry-packages"}},"1.2.0-alpha.8":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.8","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.8","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"f43a1bb67e8ce015f425f8adde60f1c52e9d82a1","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.8.tgz","fileCount":58,"integrity":"sha512-uLvJNPM1sMuthXxUHQzRNL/3HJpaj13xCcmq4V50jDX8y/oTR+QIWM9oaJ92y2vPukQyYJSFJXIQkpdNTodPSw==","signatures":[{"sig":"MEUCIFjO+TV+3zTd35X6HPcPotehJgpV9toNPhm2leEC0Jb9AiEA2IjXxprvlY6ofMSr1S5prYGKEie/7JvRnjAlrcOYMNA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":94899},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"322119f115017f483a72356a8e1896c860dbb1fd","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.8.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.18.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.8_1695933930661_0.9675309479301661","host":"s3://npm-registry-packages"}},"1.2.0-alpha.9":{"name":"@globalid/issuer-toolkit","version":"1.2.0-alpha.9","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0-alpha.9","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"0f72926e7c83868cd92bca9dc5528ad2909f56fc","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0-alpha.9.tgz","fileCount":58,"integrity":"sha512-PSj5oODq91AbGRbboIpQBGT1RT8arjjcGNK7Vh6XsbVWVZQ+8LngxHoTkXLlSqzQ2g1Nhj+1jP48BTjiwL2h7w==","signatures":[{"sig":"MEUCIQDwMPNH/pQNnNEpZ7ydSYP9kFxf4rjIVGsUbqx+kF+GngIgY7gODzumL09BHfXfeiRD7xbBSTdQCKnntIEqHwvj45o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":94976},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"7b02b9219386a2dae7d7e0987df91675b60376bc","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.8.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.18.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0-alpha.9_1695934479723_0.0928997427196232","host":"s3://npm-registry-packages"}},"1.2.0":{"name":"@globalid/issuer-toolkit","version":"1.2.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.2.0","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"bassgetabwuu","email":"kerry.mahne@gmail.com"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"0770276ba75cc239c666ca89e9ef2484983af389","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.2.0.tgz","fileCount":58,"integrity":"sha512-1pzH2IM1UwGfIQZWLyhMge9JvwYqEm5Nv8yAGHMbgq0bPVtzm0opavjrT42HSBxYaA363GZpiW3ZrkRPYmcASw==","signatures":[{"sig":"MEUCIQCLWznIPQwJ2ziz8i6SLEk6E7rdZYQGjy+OAZofQE8j8AIgAo13q2EnrpQMe7Z1RpSNOZIe7tA0E9VFuIZJpAo1EiQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":94952},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"d71b9543f3162ad2c6113d19da90e6c5ffe2f8dc","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"9.8.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"18.18.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.2.0_1695992583124_0.5556004017970817","host":"s3://npm-registry-packages"}},"1.3.0-alpha.1":{"name":"@globalid/issuer-toolkit","version":"1.3.0-alpha.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.3.0-alpha.1","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"1f6a4e72eb4df65896ce5e40d6213fcd381c8840","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.3.0-alpha.1.tgz","fileCount":60,"integrity":"sha512-vniIitw5yMWBvvDXvwV+Ev/mV5j8G/08FYirmGfFRhdNtBeYP37KJBYC+cOlI6LySPv0e0Ue5z2VoS4SfHod/g==","signatures":[{"sig":"MEQCIAnmWUTi2WMQNvSCOQqG4sHEqgiQWwA4kgCGZBr38hw/AiBJjLbYr4J9Hvf3Cqblon1ZinkT3COh0TSzy46quP8m6Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":100880},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"873ac3f61c1c816c4afb49a49b2d1994260c1291","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.2.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"20.10.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.3.0-alpha.1_1703543822989_0.747003055286146","host":"s3://npm-registry-packages"}},"1.3.0-alpha.2":{"name":"@globalid/issuer-toolkit","version":"1.3.0-alpha.2","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.3.0-alpha.2","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"517504c6e453043c2c945b4a4f2d6480e77ce234","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.3.0-alpha.2.tgz","fileCount":60,"integrity":"sha512-zaA0yOLxMajh1yeavNDxadN3TplH2bB0oeATTEHRFt0/MBqOvSUluh7EOU2JOEhU00vqFFbKceCA4yvoaytONQ==","signatures":[{"sig":"MEUCIBUDt63jyo5oAnLtjlYfGUX6a3Vw5uFcXOPTpXBMEcYdAiEA19dpCMTpxt1sx0A8IFOLTnEjMW0ERAcYm4YjLd4yUvg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":100886},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"7c77b711ae767a978bac33757c1f757c98776307","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.2.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"20.10.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.3.0-alpha.2_1703632190368_0.2661351101480147","host":"s3://npm-registry-packages"}},"1.3.0":{"name":"@globalid/issuer-toolkit","version":"1.3.0","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.3.0","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"janina_gea","email":"janina@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"9ad764acbac0ccfbd8737330a679d03f22472523","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.3.0.tgz","fileCount":60,"integrity":"sha512-DFaamSDyYbLPXWkCGXx1cAC1gQL7ZXNl5s/eZTHj5asYhwD7GnmSZa883UNZfAp3v18Jw1/2TTn4WAlpu4upfQ==","signatures":[{"sig":"MEUCIQDDwz7ZOEV4DwadNX9v32Ubea3+N1m7Q5oHg0t1lsx6qwIgFogfzGVI+3ULa9L5ZVIE1XVZaSdHtoMD0rP7Wm+qUWY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":100862},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"7c77b711ae767a978bac33757c1f757c98776307","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.2.3","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"20.10.0","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.3.0_1704326277772_0.2363341224768316","host":"s3://npm-registry-packages"}},"1.4.0-alpha.2":{"name":"@globalid/issuer-toolkit","version":"1.4.0-alpha.2","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.4.0-alpha.2","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"71a42d89d4d3dd9f6447e567420d8b85ee734c6e","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.4.0-alpha.2.tgz","fileCount":60,"integrity":"sha512-Prl031QZooiPAWGsYiR/VulgsTDHFK/q5RB6pSQnKdsWAfCORf//Eji9xkcB/vX9nwciH3WbDY1RpQNkp5ClaA==","signatures":[{"sig":"MEUCIFHO9EpUum32Rgln8+arzpxa3EyqvLUVzOjQbvndSu2nAiEA2m7Pv0DDmGnpCHgpwhMZW2QclB4Vvh4mKBVcRe/Tw2Q=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":98679},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"fb9d07838cd442791ffd096978581a81e6354c64","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"cotko","email":"mitja.cotic@globalid.net"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.5.1","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"21.7.2","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.4.0-alpha.2_1712909181918_0.13159901058694223","host":"s3://npm-registry-packages"}},"1.4.0-alpha.6":{"name":"@globalid/issuer-toolkit","version":"1.4.0-alpha.6","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.4.0-alpha.6","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"5c7932cf3f20e441329f582e89d0b9f5502788b8","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.4.0-alpha.6.tgz","fileCount":60,"integrity":"sha512-EGKljNfRWfUnnW6BKrD+bf9amKq1UkgbQdAFWB525BIGj7yuUZ2yerEQuzSU0/et/YzFvMfRiUayobW9xFKg1w==","signatures":[{"sig":"MEQCIAkzalHlujCtFGa1b7vo77pM4qIFwrK5d7WV2F3jNm4tAiAvZXsZ2HJ5ENzPVj+npO4FKBUfUXP7o+kHHu9m7QusIg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":98679},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"2b2d4faae0c882884cc4106d9d68772ba58cb2bb","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"20.12.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.4.0-alpha.6_1712912202153_0.8202347541251631","host":"s3://npm-registry-packages"}},"1.4.0-alpha.15":{"name":"@globalid/issuer-toolkit","version":"1.4.0-alpha.15","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.4.0-alpha.15","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"55bde0462b0c36e55c3b5600ecd00eab3db4f0bc","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.4.0-alpha.15.tgz","fileCount":60,"integrity":"sha512-bRYHhr/DoZ90itAIRCV5A7T0HD8A1+HSiDRj+6V+QK1opxyQdDCOEUCEWVxYaiaI0aLk6NTsFvDZuRFTDGyupA==","signatures":[{"sig":"MEYCIQD7fnfihIR2YZHK0mkK2GAm2Svw8P3987cXrf3RRnGODAIhANOfWSz7PdmWNpPe5W65ku91iOQK948vBcUgN2O0BCSJ","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":98682},"main":"dist/index.js","types":"dist/index.d.ts","readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","gitHead":"5555263c743bab9e810e52646548bab5ff58c7af","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"20.12.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.4.0-alpha.15_1712928914931_0.20237424839806128","host":"s3://npm-registry-packages"}},"1.4.1":{"name":"@globalid/issuer-toolkit","version":"1.4.1","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"author":{"name":"GlobaliD"},"license":"Apache-2.0","_id":"@globalid/issuer-toolkit@1.4.1","maintainers":[{"name":"npm-gid","email":"npm@global.id"},{"name":"vojkoro","email":"vojko.rozic@global.id"},{"name":"jantomsic","email":"jan.tomsic@global.id"},{"name":"dodosan89","email":"darjan@global.id"},{"name":"qloud.io","email":"accounts@qloud.io"},{"name":"msim","email":"mitja@global.id"},{"name":"anton.svetin","email":"anton.svetin@gmail.com"},{"name":"cotko","email":"mitja.cotic@globalid.net"},{"name":"brankoqa","email":"branko.daskijevic@global.id"},{"name":"ctomc","email":"tomaz.cerar@gmail.com"},{"name":"akovac","email":"anze@kovac.si"},{"name":"anzeloviscek","email":"anze.loviscek@global.id"},{"name":"andrej111","email":"andrej@global.id"},{"name":"akvarij","email":"aljaz.resnik@global.id"},{"name":"nejc.tomazic","email":"nejc.tomazic@global.id"},{"name":"bojanradenovic","email":"bojan@global.id"},{"name":"gaspervrhovsekglobalid","email":"gasper.vrhovsek@global.id"},{"name":"nejcpusnik","email":"nejc.pusnik@global.id"}],"homepage":"https://github.com/globalid/issuer-toolkit#readme","bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"dist":{"shasum":"059a793ab99c753a7419a1cdb160fca41439cd87","tarball":"https://registry.npmjs.org/@globalid/issuer-toolkit/-/issuer-toolkit-1.4.1.tgz","fileCount":60,"integrity":"sha512-6pzCfPnkiLN3v6FGdqeZ4g+VBor9trVsQe3WONgHnLO5M9a81U5wGzBSrQAcdTloNzOdwcbkh/B1iFgBB2PWPw==","signatures":[{"sig":"MEUCIQCt8zSOPzua0w/DEmjx5qyQdqY/Q+9su4OK6/f0T7gkDgIgDxuc+jhPDl++pj9uD9uwHEfAtmiaeVYC7J5SIR0oOYs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":98655},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"7a8990bf918ebd115a3c98f18ac9317e35ab007a","scripts":{"lint":"eslint .","test":"jest","build":"npm run clean && npm run genver && npm run compile && npm run lint && npm run format:check","clean":"rimraf dist","format":"prettier --write .","genver":"genversion src/version.ts --es6 --semi","compile":"tsc --project tsconfig.build.json","lint:fix":"npm run lint -- --fix","test:watch":"npm run test -- --watch","postversion":"npm run genver","format:check":"prettier --check .","prepublishOnly":"npm run compile"},"_npmUser":{"name":"npm-gid","email":"npm@global.id"},"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"_npmVersion":"10.5.0","description":"Library for credential issuers integrated with GlobaliD","directories":{},"_nodeVersion":"20.12.1","dependencies":{"joi":"^17.9.1","axios":"^1.3.6","dayjs":"^1.11.7","form-data":"^4.0.0","globalid-crypto-library":"^5.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","nock":"^13.3.0","sinon":"^15.0.3","eslint":"^8.38.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","ts-node":"^10.9.1","prettier":"^2.8.7","genversion":"^3.1.1","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.15.12","@types/sinon":"^10.0.14","@golevelup/ts-jest":"0.3.5","eslint-plugin-jest":"^27.2.1","eslint-config-prettier":"^8.8.0","@typescript-eslint/parser":"^5.59.0","@typescript-eslint/eslint-plugin":"^5.59.0"},"_npmOperationalInternal":{"tmp":"tmp/issuer-toolkit_1.4.1_1713261115902_0.13119331009076496","host":"s3://npm-registry-packages"}}},"time":{"created":"2022-01-25T15:16:42.928Z","modified":"2026-01-09T10:10:29.677Z","0.2.0-alpha.1":"2022-01-25T15:16:43.081Z","0.2.0":"2022-01-25T23:19:08.087Z","0.2.1-alpha.2":"2022-03-08T16:24:55.759Z","0.2.1-alpha.3":"2022-03-08T18:16:44.166Z","0.2.1-alpha.4":"2022-03-08T23:10:25.415Z","0.2.1-alpha.5":"2022-03-08T23:33:47.722Z","0.2.1-alpha.7":"2022-03-09T18:18:25.522Z","0.2.1-alpha.9":"2022-03-15T16:55:34.035Z","0.2.1":"2022-03-16T21:04:10.039Z","0.2.3-alpha.3":"2022-04-11T10:35:15.554Z","0.3.0":"2022-05-11T22:38:01.524Z","0.4.0-alpha.2":"2022-05-24T15:20:23.073Z","0.4.0-alpha.3":"2022-05-27T14:47:10.792Z","0.4.0":"2022-06-01T14:45:54.225Z","0.4.1-alpha.3":"2022-06-03T18:20:43.017Z","0.4.1-alpha.6":"2022-06-29T15:50:52.476Z","0.4.1-alpha.7":"2022-06-30T19:50:04.798Z","0.4.1-alpha.8":"2022-08-23T15:25:37.124Z","0.4.2-alpha.1":"2022-08-31T12:35:51.012Z","0.4.1":"2022-09-05T09:30:16.066Z","0.5.0-alpha.1":"2023-02-13T12:19:17.977Z","0.5.0-alpha.2":"2023-02-13T12:35:11.986Z","0.5.0-alpha.3":"2023-02-13T14:07:22.021Z","0.5.0-alpha.5":"2023-02-14T12:27:21.331Z","0.5.0":"2023-02-17T11:15:57.556Z","0.6.0-alpha.3":"2023-03-30T15:45:56.818Z","0.6.0-alpha.5":"2023-04-03T12:59:39.342Z","0.6.0":"2023-04-04T10:49:01.707Z","0.6.1":"2023-04-20T08:26:20.271Z","0.6.2-alpha.3":"2023-06-13T09:41:31.744Z","1.0.0":"2023-06-16T08:20:07.852Z","1.1.0-alpha.4":"2023-08-08T10:58:08.071Z","1.1.0-alpha.5":"2023-08-08T12:19:30.297Z","1.1.0-alpha.6":"2023-08-08T12:23:07.228Z","1.1.0-alpha.7":"2023-08-08T12:31:59.884Z","1.1.0-alpha.8":"2023-08-09T07:11:33.505Z","1.1.0-alpha.9":"2023-08-09T07:58:58.451Z","1.1.0":"2023-09-11T07:38:44.788Z","1.2.0-alpha.2":"2023-09-26T11:03:50.711Z","1.2.0-alpha.3":"2023-09-26T19:36:55.569Z","1.2.0-alpha.4":"2023-09-27T09:21:48.203Z","1.2.0-alpha.5":"2023-09-27T10:08:34.282Z","1.2.0-alpha.6":"2023-09-28T18:54:41.724Z","1.2.0-alpha.7":"2023-09-28T19:20:52.441Z","1.2.0-alpha.8":"2023-09-28T20:45:30.891Z","1.2.0-alpha.9":"2023-09-28T20:54:39.945Z","1.2.0":"2023-09-29T13:03:03.309Z","1.3.0-alpha.1":"2023-12-25T22:37:03.160Z","1.3.0-alpha.2":"2023-12-26T23:09:50.517Z","1.3.0":"2024-01-03T23:57:57.977Z","1.4.0-alpha.2":"2024-04-12T08:06:22.110Z","1.4.0-alpha.6":"2024-04-12T08:56:42.301Z","1.4.0-alpha.15":"2024-04-12T13:35:15.097Z","1.4.1":"2024-04-16T09:51:56.094Z"},"bugs":{"url":"https://github.com/globalid/issuer-toolkit/issues"},"author":{"name":"GlobaliD"},"license":"Apache-2.0","homepage":"https://github.com/globalid/issuer-toolkit#readme","keywords":["credential","decentralized","identity","issuer","self-sovereign","SSI","verifiable"],"repository":{"url":"git+https://github.com/globalid/issuer-toolkit.git","type":"git"},"description":"Library for credential issuers integrated with GlobaliD","maintainers":[{"email":"accounts@qloud.io","name":"qloud.io"},{"email":"mitja@global.id","name":"msim"},{"email":"mitja.cotic@globalid.net","name":"cotko"},{"email":"anze@kovac.si","name":"akovac"},{"email":"anze.loviscek@global.id","name":"anzeloviscek"},{"email":"andrej@global.id","name":"andrej111"},{"email":"aljaz.resnik@global.id","name":"akvarij"},{"email":"bojan@global.id","name":"bojanradenovic"},{"email":"gasper.vrhovsek@global.id","name":"gaspervrhovsekglobalid"},{"email":"nejc.pusnik@global.id","name":"nejcpusnik"},{"email":"artem.pylypchuk@global.id","name":"articice_globalid"},{"email":"npm@global.id","name":"npm-gid"},{"email":"yehor.krasnov@global.id","name":"yehorkrasnov"},{"email":"ratko.kostov@global.id","name":"ratkokostov"},{"email":"matjaz.cuk@global.id","name":"mcuk-globalid"},{"email":"gregor.stamac@gmail.com","name":"gstamac"},{"email":"cuderman.andraz@gmail.com","name":"acuderman"},{"email":"aleksander.arun.bahl@global.id","name":"aleksanderarunbahl_gid"}],"readme":"# Issuer Toolkit\n\nThis is a library for credential issuers integrated with GlobaliD.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Validating a Credential Request](#validating-a-credential-request)\n  - [Uploading a File](#uploading-a-file)\n  - [Sending a Credential Offer](#sending-a-credential-offer)\n  - [Reporting an Error](#reporting-an-error)\n    - [Error Codes](#error-codes)\n  - [Downloading a File](#downloading-a-file)\n  - [Testing Utilities](#testing-utilities)\n    - [Nock](#nock)\n    - [Sinon](#sinon)\n- [TypeScript](#typescript)\n- [Development](#development)\n\n## Installation\n\n```sh\nnpm install @globalid/issuer-toolkit\n```\n\n## Usage\n\nThe `GidIssuerClient` class is the primary component of the toolkit, providing several methods for issuing a credential.\n\nThe function to create a `GidIssuerClient` requires the client ID and secret of a developer app created in [GlobaliD's developer portal](https://developer.global.id/).\n\n```js\nconst clientId = '...';\nconst clientSecret = '...';\nconst client = createGidIssuerClient(clientId, clientSecret);\n```\n\nThe `GidIssuerClient` supports the typical flow for issuing a credential:\n\n1. Receive and [validate a credential request](#validating-a-credential-request).\n1. [Encrypt and upload file claims](#uploading-a-file) (optional).\n1. Build and [send a credential offer](#sending-a-credential-offer).\n\nIf anything goes wrong in that process, issuers can [report an error](#reporting-an-error), which notifies the prospective holder of a problem in the credential issuance.\n\n### Validating a Credential Request\n\nThe `validateRequest` method will check the validity of a `CredentialRequest`, which consists of the following properties:\n\n- `data` (optional) - Information about the credential being requested\n- `gidUuid` - UUID of the holder's GlobaliD identity\n- `signature` - Result of [digitally signing](https://en.wikipedia.org/wiki/Digital_signature) the concatenation of the `timestamp`, `threadId`, and (if present) `data`, using the holder's private key\n- `threadId` - ID correlating interactions related to this credential request\n- `timestamp` - Time of the request as the number of milliseconds since the Unix epoch\n\nOf those, the `signature` and `timestamp` are validated. The `signature` is [verified](https://nodejs.org/api/crypto.html#cryptoverifyalgorithm-data-key-signature-callback) using the public key corresponding to the holder's identity (identified by `gidUuid`). The `timestamp` must be no more than 5 minutes in the past or 1 minute in the future. If the credential request is invalid, an error is thrown.\n\nThis method also handles boilerplate [error reporting](#reporting-an-error). An `InvalidSignatureError`, `StaleRequestError`, or `EagerRequestError` is reported as a `600-16`. All other errors are reported as a `600-7`.\n\n```js\nconst threadId = '...';\nconst gidUuid = '...';\nconst credentialRequest = {\n  threadId,\n  gidUuid,\n  timestamp: 1640995200000,\n  signature: 'abcdefghijklmnopqrstuvwxyz',\n  data: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30'\n  }\n};\n\ntry {\n  await client.validateRequest(credentialRequest);\n} catch (error) {\n  if (error instanceof IdentityNotFoundError) {\n    // invalid identity (i.e., `gidUuid` does not exist)\n  } else if (error instanceof PublicKeyNotFoundError) {\n    // user has no public key\n  } else if (error instanceof InvalidSignatureError) {\n    // `signature` is invalid\n  } else if (error instanceof StaleRequestError || error instanceof EagerRequestError) {\n    // `timestamp` is outside acceptable range\n  }\n}\n```\n\n### Uploading a File\n\nThe `uploadFile` method allows for encrypting and uploading a file to GlobaliD's S3 instance. The file is encrypted using AES and a randomly-generated 256-bit key, which is itself encrypted using the holder's public key.\n\n```js\nconst fileClaim = await client.uploadFile(gidUuid, {\n  name: '8bfd3afe-8f0b-4583-836e-97cde534e304.foo.jpg',\n  type: 'image/jpeg',\n  content: Buffer.from(/* ... */)\n});\n```\n\nThe result of `uploadFile` is a `FileClaimValue` intended for use in a `CredentialOffer` (see [Sending a Credential Offer](#sending-a-credential-offer)). A `FileClaimValue` has the following properties:\n\n- `decryptionKey` - Symmetric key used to decrypt (via AES) the payload received by dereferencing the `url`. The key is encrypted using RSA and the holder's public key.\n- `sha512sum` - Checksum of the file's content\n- `type` - Media type of the file's content\n- `url` - Location of the encrypted file\n\n### Sending a Credential Offer\n\nThe `sendOffer` method allows sending an offer for a credential following a credential request. The method accepts a `CredentialOffer`, which has the following properties:\n\n- `claims` - Claims about the credential subject\n- `contextUri` - URI of a JSON-LD context describing the credential subject\n- `description` (optional) - Descriptive text about the credential being offered\n- `name` - Name of the credential being offered\n- `schemaUri` - URI of a JSON Schema describing the data schema of the credential subject's claims\n- `subjectType` - JSON-LD `@type` of the credential subject\n- `threadId` - ID correlating interactions related to this credential request\n\n```js\nconst claims = ;\n\nconst credentialOffer = {\n  threadId,\n  name: 'Government ID',\n  description: 'Lorem ipsum dolor sit amet',\n  contextUri: 'https://example.com/contexts/Person',\n  schemaUri: 'https://example.com/schemas/Person',\n  subjectType: 'Person',\n  claims: {\n    givenName: 'Neville',\n    birthDate: '1980-07-30',\n    avatar: fileClaim\n  }\n};\n\nawait client.sendOffer(credentialOffer);\n```\n\n### Reporting an Error\n\nIf something goes wrong while fulfilling a credential request, you can report the error using the `reportError` method.\n\n```js\nawait client.reportError(threadId, '600-1');\n```\n\n#### Error Codes\n\n| Code     | Description                                                   |\n| -------- | ------------------------------------------------------------- |\n| `300-8`  | Document unsupported                                          |\n| `600-1`  | General credential request failure                            |\n| `600-3`  | Verification process was cancelled                            |\n| `600-7`  | GlobaliD erred or is unavailable                              |\n| `600-8`  | Issuer is unavailable                                         |\n| `600-16` | [Request validation](#validating-a-credential-request) failed |\n\n### Downloading a File\n\nThe toolkit offers the `downloadFile` utility function for downloading and optionally decrypting a file from a URL, presumably sent in the initial credential request. This function is essentially the inverse of `GidIssuerClient`'s `uploadFile`.\n\nIn addition to a URL string, `downloadFile` accepts the following options:\n\n- `decryptionKey` - Symmetric key used to decrypt the downloaded file via AES. The file is assumed to be in plaintext if this option is absent.\n- `privateKey` - Asymmetric private key (typically the issuer's) used to decrypt the `decryptionKey` via RSA. The `decryptionKey` is assumed to be plaintext if this option is absent.\n- `sha512sum` - Checksum used to validate the integrity of the downloaded (and possibly decrypted) file\n\n```js\nimport { downloadFile } from '@globalid/issuer-toolkit';\n\nconst buffer1 = await downloadFile('http://example.com/unencrypted-file');\nconst buffer2 = await downloadFile('https://example.com/encrypted-file', {\n  decryptionKey: request.data.avatar.key,\n  privateKey: process.env.PRIVATE_KEY,\n  sha512sum: request.data.avatar.checksum\n});\n```\n\n### Testing Utilities\n\n#### Nock\n\nThe `@globalid/issuer-toolkit/testing` module provides functions for mocking the HTTP requests (using [`nock`](https://npmjs.com/package/nock)) made by `GidIssuerClient`. There are `mock*` functions for each `GidIssuerClient` method, as well as a `clearMocks` function for cleanup.\n\n```js\nimport * as GidIssuerClient from '@globalid/issuer-toolkit/testing';\n\nafterEach(() => {\n  GidIssuerClient.clearMocks();\n});\n\ntest('request validation', async () => {\n  GidIssuerClient.mockValidateRequest(gidUuid, publicKey);\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClient.mockSendOffer();\n  // ...\n});\n```\n\n#### Sinon\n\nThe `@globalid/issuer-toolkit/testing/sinon` allows [Sinon](https://sinonjs.org/) users to create a `GidIssuerClient` stub.\n\n```js\nimport stubGidIssuerClient from '@globalid/issuer-toolkit/testing/sinon';\nimport sinon from 'sinon';\n\nconst GidIssuerClientStub = stubGidIssuerClient();\n\nafterEach(() => {\n  sinon.restore();\n});\n\ntest('request validation', async () => {\n  GidIssuerClientStub.validateRequest.withArgs(/* ... */).resolves();\n\n  // call your code that uses GidIssuerClient#validateRequest...\n\n  // assertions...\n});\n\ntest('sending an offer', async () => {\n  GidIssuerClientStub.sendOffer.withArgs(/* ... */).resolves();\n  // ...\n});\n```\n\n## TypeScript\n\nThe issuer toolkit is written in TypeScript, so type declarations are bundled with the package.\n\n## Development\n\nThe following NPM scripts are available for development:\n\n- `build` – Runs the `clean`, `genver`, `compile`, `lint`, and `format:check` scripts to build the project\n- `clean` – Removes the output directory for a clean build\n- `compile` – Compiles TypeScript files with `tsc`\n- `format` – Formats the files with [Prettier](https://prettier.io/)\n- `format:check` – Checks the formatting of the files with Prettier\n- `genver` - Generates a version module with [`genversion`](https://www.npmjs.com/package/genversion)\n- `lint` – Lints the code with [ESLint](https://eslint.org/)\n- `lint:fix` – Attempts to fix problems found by the linter\n- `test` – Tests the code with [Jest](https://jestjs.io/)\n- `test:watch` – Tests the code in watch mode\n","readmeFilename":"README.md"}