feathers-ucan 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/env/version.d.ts +1 -1
- package/lib/hooks/ucan-auth.d.ts +1 -1
- package/lib/index.cjs +1020 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.modern.js +998 -1
- package/lib/index.modern.js.map +1 -1
- package/lib/index.umd.js +1023 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +2 -2
package/lib/index.cjs
CHANGED
|
@@ -1,2 +1,1021 @@
|
|
|
1
|
-
var e=require("symbol-ucan"),t=require("@feathersjs/authentication");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/n(require("long-timeout"));function i(e){function t(e){if(Object(e)!==e)return Promise.reject(new TypeError(e+" is not an object."));var t=e.done;return Promise.resolve(e.value).then(function(e){return{value:e,done:t}})}return i=function(e){this.s=e,this.n=e.next},i.prototype={s:null,n:null,next:function(){return t(this.n.apply(this.s,arguments))},return:function(e){var n=this.s.return;return void 0===n?Promise.resolve({value:e,done:!0}):t(n.apply(this.s,arguments))},throw:function(e){var n=this.s.return;return void 0===n?Promise.reject(e):t(n.apply(this.s,arguments))}},new i(e)}function o(){return o=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o.apply(this,arguments)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,u(e,t)}function c(e){return c=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},c(e)}function u(e,t){return u=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},u(e,t)}function s(e,t,n){return s=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}()?Reflect.construct.bind():function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&u(i,n.prototype),i},s.apply(null,arguments)}function l(e){var t="function"==typeof Map?new Map:void 0;return l=function(e){if(null===e||!function(e){try{return-1!==Function.toString.call(e).indexOf("[native code]")}catch(t){return"function"==typeof e}}(e))return e;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return s(e,arguments,c(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),u(n,e)},l(e)}function f(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(i[n]=e[n]);return i}function h(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function p(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(n)return(n=n.call(e)).next.bind(n);if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return h(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?h(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0;return function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var v=/*#__PURE__*/function(e){function t(t){return e.call(this,t)||this}return a(t,e),t}(/*#__PURE__*/l(Error)),d=/(\S+)\s+(\S+)/,y=/*#__PURE__*/function(t){function n(){for(var e,n=arguments.length,r=new Array(n),i=0;i<n;i++)r[i]=arguments[i];return(e=t.call.apply(t,[this].concat(r))||this).expirationTimers=new WeakMap,e}a(n,t);var i,c,u=n.prototype;return u.setAuthentication=function(e){e.verifyAccessToken=function(e){return{}},t.prototype.setAuthentication.call(this,e)},u.handleConnection=function(t,n,i){try{var o=this,a="logout"===t&&n.authentication&&i&&n.authentication.accessToken===i.accessToken,c=(i||{}).accessToken,u=function(){if(c&&"login"===t)return Promise.resolve(e.validateUcan(c).catch(function(e){console.log("Could not validate ucan in connection: ",e.message);var t={code:0,message:"Unknown Issue Validating Ucan"};throw e.message.indexOf("Expired.")>-1&&(t.code=1,t.message="Expired Ucan"),new Error(t.message)})).then(function(e){var t=1e3*(e||{payload:{exp:0}}).payload.exp-Date.now(),i=r.default.setTimeout(function(){return o.app.emit("disconnect",n)},t);r.default.clearTimeout(o.expirationTimers.get(n)),o.expirationTimers.set(n,i),n.authentication={strategy:o.name,accessToken:c}});("disconnect"===t||a)&&(delete n[o.configuration.entity],delete n.authentication,r.default.clearTimeout(o.expirationTimers.get(n)),o.expirationTimers.delete(n))}();return Promise.resolve(u&&u.then?u.then(function(){}):void 0)}catch(e){return Promise.reject(e)}},u.verifyConfiguration=function(){for(var e=["entity","entityId","service","header","schemes","audience"],t=0,n=Object.keys(this.configuration);t<n.length;t++){var r=n[t];if(!e.includes(r))throw new Error("Invalid ucanStrategy option 'authentication."+this.name+"."+r+"'. Did you mean to set it in 'authentication.jwtOptions'?")}if("string"!=typeof this.configuration.header)throw new Error("The 'header' option for the "+this.name+" strategy must be a string")},u.getEntityQuery=function(e){return Promise.resolve({})},u.getEntity=function(t,n){try{var r=this,i=r.entityService,a=r.configuration.entity;if(null===i)throw new v("Could not find entity service");return Promise.resolve(r.getEntityQuery(n)).then(function(r){var c=Object.assign({},e._unset(n,"provider"),{query:r});return Promise.resolve(i.get(t,c)).then(function(e){var r;return n.provider?i.get(t,o({},n,((r={})[a]=e,r))):e})})}catch(e){return Promise.reject(e)}},u.getEntityId=function(e,t){try{var n=t.query,r=t.loginId;if(r)return Promise.resolve(r);var i,a,c=this.configuration,u=c.service,s=c.core_path,l=void 0===s?"core":s,f=((i={query:o({},n,{$limit:1})})[l]=o({skipJoins:!0},t[l]),i);return Promise.resolve(null==(a=this.app)?void 0:a.service(u).find(o({},f,{skipJoins:!0,skip_hooks:!0,admin_pass:!0}))).then(function(e){if(e.total)return e.data[0]._id;throw new v("Could not find login associated with this ucan")})}catch(e){return Promise.reject(e)}},u.authenticate=function(t,n){try{var r=this,i=t.accessToken,a=t.loginId,c=t.ucan,u=r.configuration,s=u.entity,l=u.core_path;if(!i){if(!c)throw new v("Error generating ucan");i=e.ucanToken(c)}return Promise.resolve(e.validateUcan(i).catch(function(e){console.log("Could not validate ucan during authentication: ",e.message);var t={code:0,message:"Unknown Issue Validating Ucan"};throw e.message.indexOf("Expired.")>-1&&(t.code=1,t.message="Expired Ucan"),new Error(t.message)})).then(function(t){function c(){var e;return o({},f,((e={})[s]=u,e))}var u,f={accessToken:i,authentication:{strategy:"jwt",accessToken:i}};if(null===s)return f;var h=e._get(n,[l,s]),p=function(){if(!h)return Promise.resolve(r.getEntityId(f,o({},n,{loginId:a,query:{did:null==t?void 0:t.payload.aud}}))).then(function(e){return Promise.resolve(r.getEntity(e,n)).then(function(e){u=e})});u=h}();return p&&p.then?p.then(c):c()})}catch(e){return Promise.reject(e)}},u.parse=function(e){try{var t=this.configuration,n=t.schemes,r=e.headers&&e.headers[t.header.toLowerCase()];if(!r||"string"!=typeof r)return Promise.resolve(null);var i=r.match(d)||[],o=i[1],a=i[2],c=o&&n.some(function(e){return new RegExp(e,"i").test(o)});return Promise.resolve(o&&!c?null:{strategy:this.name,accessToken:c?a:r})}catch(e){return Promise.reject(e)}},i=n,(c=[{key:"configuration",get:function(){var e,n=(null==(e=this.authentication)?void 0:e.configuration)||{service:void 0,entity:void 0,entityId:void 0};return o({service:n.service,entity:n.entity,entityId:n.entityId,header:"Authorization",schemes:["Bearer","JWT"]},t.prototype.configuration)}}])&&function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,"symbol"==typeof(i=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(r.key))?i:String(i),r)}var i}(i.prototype,c),Object.defineProperty(i,"prototype",{writable:!1}),n}(t.AuthenticationBaseStrategy),g=["NotAuthenticated"],m=/*#__PURE__*/function(e){function t(t){return e.call(this,t)||this}return a(t,e),t}(/*#__PURE__*/l(Error)),P=/*#__PURE__*/function(t){function n(e,n,r){var i;void 0===n&&(n="authentication"),void 0===r&&(r={});var o=r.NotAuthenticated,a=f(r,g);return(i=t.call(this,e,n,a)||this).options=void 0,i.app=e,i.options={NotAuthenticated:o},i}return a(n,t),n.prototype.create=function(t,n){try{var r,i,a=this,c=(null==(r=a.options)?void 0:r.NotAuthenticated)||m,u=a.app.get("authentication"),s=u.entity,l=u.service,f=u.ucan_path,h=void 0===f?"ucan":f,p=(null==(i=n)?void 0:i.authStrategies)||a.configuration.authStrategies;if(n||(n={}),!p.length)throw new c("No authentication strategies allowed for creating a JWT (`authStrategies`)");return Promise.resolve(a.authenticate.apply(a,[t,n].concat(p)).catch(function(e){throw new Error(e.message)})).then(function(r){if(r.accessToken)return r;var i=t.did||e._get(r,[s,"did"]),c=t.ucan||e._get(r,[s,"ucan"]);if(!i)throw new Error("No did audience provided");if(!c)throw new Error("No ucan provided to authentication call");return Promise.resolve(e.validateUcan(c).catch(function(e){console.log("Could not validate ucan creating authentication: ",e.message);var t={code:0,message:"Unknown Issue Validating Ucan"};return e.message.indexOf("Expired.")>-1&&(t.code=1,t.message="Expired Ucan"),console.warn("Could not validate ucan creating authentication",c,t.message),null})).then(function(t){function i(){var t=e.ucanToken(c);return o({accessToken:t},r,{authentication:o({},r.authentication,{payload:t})})}var u=function(){if(!t){var i=e.parseUcan(c),u=a.app.get("authentication"),f=e.encodeKeyPair({secretKey:u.secret});return Promise.resolve(e.buildUcan({audience:i.payload.aud,issuer:f,lifetimeInSeconds:5184e3,capabilities:i.payload.att})).then(function(t){var i;return c=t,n.admin_pass=!0,Promise.resolve(a.app.service(l).patch(e._get(r,[s,"_id"]),(i={},i[h]=e.ucanToken(c),i),o({},n))).then(function(){})})}}();return u&&u.then?u.then(i):i()})})}catch(e){return Promise.reject(e)}},n}(t.AuthenticationService),_=/*#__PURE__*/function(){function e(e,t,n){var r;this.context=void 0,this.service=void 0,this.core=void 0,this.entity=void 0,this.service=e,this.context=t;var i=(t.app.get("authentication")||{entity:"login"}).entity||"login";this.entity=i;var a=(null==(r=t.params)?void 0:r.core)||{};a[i]||(a[i]=t.params[i]),this.core=o({},a,n)}var t=e.prototype;return t.get=function(e,t){void 0===t&&(t={});try{var n,r,i,a=this,c=a.context.app.get("authentication").core_path;return Promise.resolve(null==(n=a.context.app)?void 0:n.service(a.service).get(e,o({},t,((r={})[a.entity]=t[a.entity],r),((i={})[c]=a.core,i))))}catch(e){return Promise.reject(e)}},t.find=function(e){void 0===e&&(e={});try{var t,n,r,i=this,a=i.context.app.get("authentication").core_path;return Promise.resolve(null==(t=i.context.app)?void 0:t.service(i.service).find(o({},e,((n={})[i.entity]=e[i.entity],n.skip_hooks=!0,n.admin_pass=!0,n),((r={})[a]=i.core,r))))}catch(e){return Promise.reject(e)}},t.create=function(e,t){void 0===t&&(t={});try{var n,r,i,a=this,c=a.context.app.get("authentication").core_path;return Promise.resolve(null==(n=a.context.app)?void 0:n.service(a.service).create(e,o({},t,((r={})[a.entity]=t[a.entity],r),((i={})[c]=a.core,i))))}catch(e){return Promise.reject(e)}},t.patch=function(e,t,n){void 0===n&&(n={});try{var r,i,a,c=this,u=c.context.app.get("authentication").core_path;return Promise.resolve(null==(r=c.context.app)?void 0:r.service(c.service).patch(e,t,o({},n,((i={})[c.entity]=n[c.entity],i),((a={})[u]=c.core,a))))}catch(e){return Promise.reject(e)}},t.update=function(e,t,n){void 0===n&&(n={});try{var r,i,a,c=this,u=c.context.app.get("authentication").core_path;return Promise.resolve(null==(r=c.context.app)?void 0:r.service(c.service).update(e,t,o({},n,((i={})[c.entity]=n[c.entity],i),((a={})[u]=c.core,a))))}catch(e){return Promise.reject(e)}},t.remove=function(e,t){void 0===t&&(t={});try{var n,r,i,a=this,c=a.context.app.get("authentication").core_path;return Promise.resolve(null==(n=a.context.app)?void 0:n.service(a.service).remove(e,o({},t,((r={})[a.entity]=t[a.entity],r),((i={})[c]=a.core,i))))}catch(e){return Promise.reject(e)}},t._get=function(e,t){void 0===t&&(t={});try{var n,r,i,a=this,c=a.context.app.get("authentication").core_path;return Promise.resolve(null==(n=a.context.app)?void 0:n.service(a.service)._get(e,o({},t,((r={})[a.entity]=t[a.entity],r),((i={})[c]=a.core,i))))}catch(e){return Promise.reject(e)}},t._find=function(e){void 0===e&&(e={});try{var t,n,r,i=this,a=i.context.app.get("authentication").core_path;return Promise.resolve(null==(t=i.context.app)?void 0:t.service(i.service)._find(o({},e,((n={})[i.entity]=e[i.entity],n),((r={})[a]=i.core,r))))}catch(e){return Promise.reject(e)}},t._create=function(e,t){void 0===t&&(t={});try{var n,r,i,a=this,c=a.context.app.get("authentication").core_path;return Promise.resolve(null==(n=a.context.app)?void 0:n.service(a.service)._create(e,o({},t,((r={})[a.entity]=t[a.entity],r),((i={})[c]=a.core,i))))}catch(e){return Promise.reject(e)}},t._patch=function(e,t,n){void 0===n&&(n={});try{var r,i,a,c=this,u=c.context.app.get("authentication").core_path;return Promise.resolve(null==(r=c.context.app)?void 0:r.service(c.service)._patch(e,t,o({},n,((i={})[c.entity]=n[c.entity],i),((a={})[u]=c.core,a))))}catch(e){return Promise.reject(e)}},t._update=function(e,t,n){void 0===n&&(n={});try{var r,i,a,c=this,u=c.context.app.get("authentication").core_path;return Promise.resolve(null==(r=c.context.app)?void 0:r.service(c.service)._update(e,t,o({},n,((i={})[c.entity]=n[c.entity],i),((a={})[u]=c.core,a))))}catch(e){return Promise.reject(e)}},t._remove=function(e,t){void 0===t&&(t={});try{var n,r,i,a=this,c=a.context.app.get("authentication").core_path;return Promise.resolve(null==(n=a.context.app)?void 0:n.service(a.service)._remove(e,o({},t,((r={})[a.entity]=t[a.entity],r),((i={})[c]=a.core,i))))}catch(e){return Promise.reject(e)}},e}(),b="_exists",w=function(t){var n=t.app.get("existsPath")||b;return e._get(t.params,"core."+n+"."+t.path+"."+t.id)||void 0},x=function(e,t){try{var n=w(e),r=function(){if(!n&&e.id)return Promise.resolve(new _(e.path,e,{skipJoins:!1!==(null==t?void 0:t.skipJoins)}).get(e.id,o({exists_check:!0,admin_pass:!0,skip_hooks:!0},(null==t?void 0:t.params)||{}))).then(function(e){n=e})}();return Promise.resolve(r&&r.then?r.then(function(){return n}):n)}catch(e){return Promise.reject(e)}},j=function(t,n){var r=t.app.get("existsPath")||b;return t.params=e._set(t.params,"core."+r+"."+t.path+"."+((null==n?void 0:n._id)||t.id),n),t},k=["ucan"];function S(e,t){try{var n=e()}catch(e){return t(e)}return n&&n.then?n.then(void 0,t):n}function A(e,t,n){if(!e.s){if(n instanceof E){if(!n.s)return void(n.o=A.bind(null,e,t));1&t&&(t=n.s),n=n.v}if(n&&n.then)return void n.then(A.bind(null,e,t),A.bind(null,e,2));e.s=t,e.v=n;var r=e.o;r&&r(e)}}const E=/*#__PURE__*/function(){function e(){}return e.prototype.then=function(t,n){const r=new e,i=this.s;if(i){const e=1&i?t:n;if(e){try{A(r,1,e(this.v))}catch(e){A(r,2,e)}return r}return this}return this.o=function(e){try{const i=e.v;1&e.s?A(r,1,t?t(i):i):n?A(r,1,n(i)):A(r,2,i)}catch(e){A(r,2,e)}},r},e}();function T(e){return e instanceof E&&1&e.s}function O(e,t,n){var r,i,o=-1;return function a(c){try{for(;++o<e.length&&(!n||!n());)if((c=t(o))&&c.then){if(!T(c))return void c.then(a,i||(i=A.bind(null,r=new E,2)));c=c.v}r?A(r,1,c):r=c}catch(e){A(r||(r=new E),2,e)}}(),r}function U(e,t,n){var r=[];for(var i in e)r.push(i);return O(r,function(e){return t(r[e])},n)}var C="undefined"!=typeof Symbol?Symbol.iterator||(Symbol.iterator=Symbol("Symbol.iterator")):"@@iterator";function I(e,t){try{var n=e()}catch(e){return t(!0,e)}return n&&n.then?n.then(t.bind(null,!1),t.bind(null,!0)):t(!1,n)}var q=function(n){try{var r,i=n.app.get("authentication"),o=e._get(n,["auth",i.entity]);o&&(n=e._set(n,[i.core_path,i.entity],o));var a=S(function(){return Promise.resolve(t.authenticate("jwt")(n).catch(function(){return n})).then(function(e){n=e})},function(){return r=1,n});return Promise.resolve(a&&a.then?a.then(function(e){return r?e:n}):r?a:n)}catch(e){return Promise.reject(e)}},$=function(n){try{var r=n.app.get("authentication"),i=e._get(n,["auth",r.entity]);return i&&(n=e._set(n,[r.core_path,r.entity],i)),Promise.resolve(t.authenticate("jwt")(n))}catch(e){return Promise.reject(e)}},N=function(t,n,r){try{return Promise.resolve(S(function(){return Promise.resolve(e.verifyUcan(t,n)).then(function(i){var a=function(a){if((null==(a=i)||!a.ok)&&n.requiredCapabilities){var c=n.requiredCapabilities.map(function(e){return"*"!==e.capability.can&&(e.capability.can.segments=["*"]),e});return r&&console.log("set new req capabilities",c,e.parseUcan(t)),Promise.resolve(e.verifyUcan(t,o({},n,{requiredCapabilities:c}))).then(function(e){i=e,r&&console.log("Second verification result:",i)})}}();return a&&a.then?a.then(function(){return i}):i})},function(e){return{ok:!1,err:[e.message]}}))}catch(e){return Promise.reject(e)}},K=function(t,n){try{var r={ok:!1,value:[]};return Promise.resolve(S(function(){var i,o=U(t,function(o){n&&console.log("or verify loop",t[o],e.parseUcan(t[o].ucan));var a=function(e){if(null==(e=r)||!e.ok){var a=t[o],c=a.ucan,u=f(a,k);return Promise.resolve(N(c,u,n)).then(function(e){r=e,n&&console.log("got in verify loop",r)})}i=1}();if(a&&a.then)return a.then(function(){})},function(){return i});return o&&o.then?o.then(function(){return r}):r},function(e){return{ok:!1,err:[e.message]}}))}catch(e){return Promise.reject(e)}},J=function(t,n,r){return function(i){try{var o,a=null==r?void 0:r.log,c=e._get(i.params,n.client_ucan),u=(null==r?void 0:r.audience)||e._get(i.params,n.ucan_aud);a&&console.log("verify against reqs",t);var s=(null==r?void 0:r.or)||[];return o=c&&("*"===s||s.includes(i.method))?function(e,n){return K((t||[]).map(function(t){return{ucan:e||c,audience:(null==n?void 0:n.aud)||u,requiredCapabilities:[t]}}),a)}:function(e,n){return N(e||c,{audience:(null==n?void 0:n.aud)||u,requiredCapabilities:t},a)},Promise.resolve(o()).then(function(t){var c,u;if(a&&console.log("first verify try",t),null!=(c=t)&&c.ok)return t;var s=((null==r?void 0:r.cap_subjects)||[]).filter(function(e){return!!e});a&&console.log("check cap_subjects",s);var l=function(){if(s){var c=(null==n?void 0:n.loginConfig)||i.app.get("authentication"),l=String(e._get(i.params,c.entity+"._id"||""));return Promise.resolve(new _(c.capability_service||"caps",i).find({query:{$limit:s.length,subject:{$in:s}},skip_hooks:!0,admin_pass:!0}).catch(function(e){return console.log("Error finding caps in ucan auth: "+e.message)})).then(function(n){var i;return a&&console.log("caps",n),function(){if(null!=n&&n.data)return function(e,t,n){if("function"==typeof e[C]){var r,i,o,a=e[C]();if(function e(c){try{for(;!((r=a.next()).done||n&&n());)if((c=t(r.value))&&c.then){if(!T(c))return void c.then(e,o||(o=A.bind(null,i=new E,2)));c=c.v}i?A(i,1,c):i=c}catch(e){A(i||(i=new E),2,e)}}(),a.return){var c=function(e){try{r.done||a.return()}catch(e){}return e};if(i&&i.then)return i.then(c,function(e){throw c(e)});c()}return i}if(!("length"in e))throw new TypeError("Object is not iterable");for(var u=[],s=0;s<e.length;s++)u.push(e[s]);return O(u,function(e){return t(u[e])},n)}(n.data,function(n){return U(n.caps||{},function(i){return a&&console.log("check cap",i,n.caps[i].logins,l),function(){if((n.caps[i].logins||[]).map(function(e){return String(e)}).includes(l)){var c=function(){var e;if(null!=r&&r.log&&console.log("tried v on cap",t),null!=(e=t)&&e.ok)return u=1,t},s=S(function(){var r=e.ucanToken(n.caps[i].ucan);a&&console.log("got ucan string",r);var c=function(){if(r)return Promise.resolve(o(r,{aud:n.did})).then(function(e){t=e,a&&console.log("tried v on cap",t)})}();if(c&&c.then)return c.then(function(){})},function(e){console.log("Error verifying ucan from cap: "+n._id+". Err:"+e.message)});return s&&s.then?s.then(c):c()}}()},function(){return i})},function(){return i})}()})}}();return l&&l.then?l.then(function(e){return u?e:t}):u?l:t})}catch(e){return Promise.reject(e)}}},R=function(t,n){var r=e.encodeKeyPair({secretKey:n.secret}).did();return Array.isArray(t)?t.map(function(t){return{capability:Array.isArray(t)?e.genCapability({with:{scheme:n.defaultScheme,hierPart:n.defaultHierPart},can:{namespace:t[0],segments:"string"==typeof t[1]?[t[1]]:t[1]}},n):e.genCapability(t,n),rootIssuer:r}}):[]},M=function(t,n){return function(r){try{var o=function(){var t,o;if(null!=(t=c)&&t.ok)return r.params.authenticated=!0,r.params.canU=!0,r;if(null!=n&&n.log&&console.log("checking special change",null==n?void 0:n.specialChange),null!=n&&n.specialChange){if("*"===n.specialChange)return r.params.canU=!0,r;if(Array.isArray(n.specialChange)&&["create","patch","update"].includes(r.method)){if(Array.isArray(r.data))throw new Error("No multi data allowed with special change");for(var u in r.data||{})if(["$set","$unset","$addToSet","$pull","$push"].includes(u)){for(var s in r.data[u]||{})if(!n.specialChange.includes(s)){var l=s.split(".");1===l.length?delete r.data[u][s]:n.specialChange.includes(l[0])||delete r.data[u][s]}}else n.specialChange.includes(u)||delete r.data[u];return r.params.canU=!0,r}}if(null!=(o=c)&&o.ok)return r.params.authenticated=!0,r.params.canU=!0,r;var f=function(e){var t;if(null!=(t=c)&&t.ok)return r.params.authenticated=!0,r.params.canU=!0,r;if(null!=n&&n.log&&console.error("Ucan capabilities requirements not met: ",c,r.type,r.path),null!=n&&n.noThrow)return r.params._no_throw_error={type:r.type,method:r.method,path:r.path},r;throw new Error("Missing proper capabilities for this action: "+r.type+": "+r.path+" - "+r.method)},h=(n||{loginPass:[[["*"],["nonExistentMethod"]]]}).loginPass,v=function(){if(null!=h&&h.length){var t,o=function(t){if(_interrupt2)return t;s&&(r=e._set(r,"data",u))},u={},s=!0,l=!1,f=!1,v=I(function(){return S(function(){var t,o,f=function(e){var t,n,r,o=2;for("undefined"!=typeof Symbol&&(n=Symbol.asyncIterator,r=Symbol.iterator);o--;){if(n&&null!=(t=e[n]))return t.call(e);if(r&&null!=(t=e[r]))return new i(t.call(e));n="@@asyncIterator",r="@@iterator"}throw new TypeError("Object is not async iterable")}(h),v=function(e,t,n){for(var r;;){var i=e();if(T(i)&&(i=i.v),!i)return o;if(i.then){r=0;break}var o=n();if(o&&o.then){if(!T(o)){r=1;break}o=o.s}if(t){var a=t();if(a&&a.then&&!T(a)){r=2;break}}}var c=new E,u=A.bind(null,c,2);return(0===r?i.then(l):1===r?o.then(s):a.then(f)).then(void 0,u),c;function s(r){o=r;do{if(t&&(a=t())&&a.then&&!T(a))return void a.then(f).then(void 0,u);if(!(i=e())||T(i)&&!i.v)return void A(c,1,o);if(i.then)return void i.then(l).then(void 0,u);T(o=n())&&(o=o.v)}while(!o||!o.then);o.then(s).then(void 0,u)}function l(e){e?(o=n())&&o.then?o.then(s).then(void 0,u):s(o):A(c,1,o)}function f(){(i=e())?i.then?i.then(l).then(void 0,u):l(i):A(c,1,o)}}(function(){function e(e){return!t&&(l=!(o=e).done)}return t?!!e(!t&&f.next()):Promise.resolve(!t&&f.next()).then(e)},function(){return!!(l=!1)},function(){var i=o.value,l=function(){if(s)return Promise.resolve(function(t){try{var i=[],o="*"===t[1],l=-1;o?l=0:(i=t[1].map(function(e){return e.split("/")[0]}),l=i.indexOf(r.method));var f=function(){if(l>-1)return Promise.resolve(x(r,{params:null==n?void 0:n.existingParams})).then(function(n){var i=!1,f=function(t,n){void 0===n&&(n="_id");var o=e._get(r.params,a.entity+"."+n);if(o&&t){var c=Array.isArray(o)?o.map(function(e){return String(e)}):[String(o)];if(Array.isArray(t))for(var u=0;u<c.length;u++){for(var s=String(c[u]),l=0;l<t.length;)String(t[l])===s?i=!0:l++;if(i)return}else if(c.includes(String(t)))return i=!0}};if(n){r=j(r,n);for(var h,v=p(t[0]||[]);!(h=v()).done;){var d=String(h.value).split("/");if(d[0].includes("*")){var y=d[0].split("*"),g=e._get(n,y[0]);if(g&&"object"==typeof g)if(Array.isArray(g))for(var m,P=p(g);!(m=P()).done&&(f(e._get(m.value,y[1]),d[1]||"_id"),!i););else for(var _ in g)if(f(e._get(g,_+"."+y[1]),d[1]||"_id"),i)break}else f(e._get(n,d[0]),d[1]||"_id")}}if(i)if(c.ok=!0,"*"===t[1]||["find","get","remove"].some(function(e){return t[1].includes(e)}))s=!1;else{var b=o?"*":t[1][l];if(b.split("/")[0]!==b)for(var w,x=p(b.split("/").slice(1).join("").split(",")||[]);!(w=x()).done;){var k=w.value,S=e._get(r.data,k);if(S)u=e._set(u,k,S);else for(var A=0,E=["$addToSet","$pull"];A<E.length;A++){var T=E[A],O=e._get(r.data,T+"."+k);O&&(u=e._set(u,T+"."+k,O))}}else s=!1}})}();return Promise.resolve(f&&f.then?f.then(function(){}):void 0)}catch(e){return Promise.reject(e)}}(i)).then(function(){});t=1}();return l&&l.then?l.then(function(){}):void 0});if(v&&v.then)return v.then(function(){})},function(e){f=!0,t=e})},function(e,n){function r(t){if(e)throw n;return n}var i=I(function(){var e=function(){if(l&&null!=_iterator.return)return Promise.resolve(_iterator.return()).then(function(){})}();if(e&&e.then)return e.then(function(){})},function(e,n){if(f)throw t;if(e)throw n;return n});return i&&i.then?i.then(r):r()});return v&&v.then?v.then(o):o(v)}}();return v&&v.then?v.then(f):f()},a=(null==n?void 0:n.loginConfig)||r.app.get("authentication"),c={ok:!1,value:[]},u=R(t,a),s=function(){if(u.length)return Promise.resolve(J(u,a,n)(r)).then(function(e){c=e});"*"!==t&&(c.ok=!0)}();return Promise.resolve(s&&s.then?s.then(o):o())}catch(e){return Promise.reject(e)}}},B=function(t,n){return function(r){try{var i,o=function(o){if(i)return o;function c(){return"*"!==t||null!=n&&n.specialChange?s?r:t?Promise.resolve(M(t,n)(r)):r:(r.params.authenticated=!!r.params[u],r)}var s=((null==n?void 0:n.adminPass)||[]).includes(r.method)&&(e._get(r.params,"admin_pass")||e._get(r.params,[a.core_path,"admin_pass"])),l=function(){if(!f&&!h)return Promise.resolve(s||null!=n&&n.specialChange?q(r):$(r)).then(function(e){r=e})}();return l&&l.then?l.then(c):c()},a=r.app.get("authentication"),c=a.core_path||"core",u=a.entity||"login",s=e._get(r.params,[c,u])||e._get(r.params,"login")||e._get(r.params.connect,u),l="string"==typeof s?s:null==s?void 0:s._id,f=!(!s||"string"!=typeof s&&!l),h=e._get(r.params,a.client_ucan||"client_ucan");null!=n&&n.log&&console.log("ucan auth","hasLogin",f,"loginId",l,"existingUcan",!!h,"core_path",c,"entity",u,"core",r.params[c],"params login",r.params.login,"required capabilities",t);var p=function(){if("$"===t||t&&"$"===t[r.method]){var e=function(e){return i=1,e};return f?e(r):Promise.resolve(q(r)).then(e)}}();return Promise.resolve(p&&p.then?p.then(o):o(p))}catch(e){return Promise.reject(e)}}};exports.AuthService=P,exports.CoreCall=_,exports.NotAuthError=m,exports.UcanStrategy=y,exports.allUcanAuth=function(t,n){return function(r){try{var i=r.app.get("authentication"),o=i.core_path||"core",a=i.entity||"login";if(!e._get(r.params,[o,a])){var c=e._get(r,["auth",a]);c&&(r=e._set(r,[o,a],c))}if("before"===r.type){var u=r.method;return Promise.resolve(t[u]||t.all?B(t[u]||t.all,n)(r):r)}return Promise.resolve(r)}catch(e){return Promise.reject(e)}}},exports.anyAuth="*",exports.bareAuth=$,exports.checkUcan=M,exports.existsPath=b,exports.getExists=w,exports.loadExists=x,exports.modelCapabilities=R,exports.noThrow="$",exports.noThrowAuth=q,exports.orVerifyLoop=K,exports.setExists=j,exports.ucanAuth=B,exports.updateUcan=function(){return function(t){try{var n=t.data,r=n.add,i=void 0===r?[]:r,a=n.remove,c=void 0===a?[]:a;if(!(null!=i&&i.length||null!=c&&c.length))throw new Error("No new capabilities passed");var u=t.app.get("authentication"),s=u.secret,l=u.ucan_aud,f=u.entity,h=u.ucan,p=e.encodeKeyPair({secretKey:s}).did(),v=e.stackAbilities([].concat(i,c));return Promise.resolve(e.verifyUcan(e._get(t.params,[f,h]),{audience:e._get(t.params,l),requiredCapabilities:v.map(function(e){return{capability:e,rootIssuer:p}})})).then(function(n){if(null==n||!n.ok)throw new Error("You don't have sufficient capabilities to grant those capabilities");var r=t.id,a=t.data.service||"logins",u=t.data.path||"ucan";return Promise.resolve(new _(a,t,{skipJoins:!0}).get(r)).then(function(n){var l=e.parseUcan(e._get(n,u)).payload,f=l.aud,h=l.att,p=l.prf,v=[].concat(h);return null!=c&&c.length&&(v=e.reduceAbilities(c,h)),null!=i&&i.length&&(v=e.stackAbilities([].concat(h,i))),Promise.resolve(e.buildUcan(o({issuer:e.encodeKeyPair({secretKey:s}),audience:f,lifetimeInSeconds:5184e3,proofs:p},t.data,{capabilities:v}))).then(function(n){var i=e.ucanToken(n);return Promise.resolve(e.validateUcan(i)).then(function(e){var n;if(!e)throw new Error("Invalid ucan generated when updating");return Promise.resolve(new _(a,t).patch(r,(n={},n[u]=i,n))).then(function(e){return t.result={raw:t.data,encoded:i,subject:e},t})})})})})}catch(e){return Promise.reject(e)}}},exports.verifyAgainstReqs=J;
|
|
1
|
+
var symbolUcan = require('symbol-ucan');
|
|
2
|
+
var authentication = require('@feathersjs/authentication');
|
|
3
|
+
var lt = require('long-timeout');
|
|
4
|
+
|
|
5
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
6
|
+
|
|
7
|
+
var lt__default = /*#__PURE__*/_interopDefaultLegacy(lt);
|
|
8
|
+
|
|
9
|
+
class NotAuthError$1 extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const SPLIT_HEADER = /(\S+)\s+(\S+)/;
|
|
15
|
+
class UcanStrategy extends authentication.AuthenticationBaseStrategy {
|
|
16
|
+
constructor(...args) {
|
|
17
|
+
super(...args);
|
|
18
|
+
this.expirationTimers = new WeakMap();
|
|
19
|
+
}
|
|
20
|
+
setAuthentication(auth) {
|
|
21
|
+
// console.log('set authentication', auth);
|
|
22
|
+
auth.verifyAccessToken = accessToken => {
|
|
23
|
+
return {};
|
|
24
|
+
};
|
|
25
|
+
super.setAuthentication(auth);
|
|
26
|
+
}
|
|
27
|
+
get configuration() {
|
|
28
|
+
var _this$authentication;
|
|
29
|
+
const authConfig = ((_this$authentication = this.authentication) == null ? void 0 : _this$authentication.configuration) || {
|
|
30
|
+
service: undefined,
|
|
31
|
+
entity: undefined,
|
|
32
|
+
entityId: undefined
|
|
33
|
+
};
|
|
34
|
+
const config = super.configuration;
|
|
35
|
+
return {
|
|
36
|
+
service: authConfig.service,
|
|
37
|
+
entity: authConfig.entity,
|
|
38
|
+
entityId: authConfig.entityId,
|
|
39
|
+
header: 'Authorization',
|
|
40
|
+
schemes: ['Bearer', 'JWT'],
|
|
41
|
+
...config
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async handleConnection(event, connection, authResult) {
|
|
45
|
+
const isValidLogout = event === 'logout' && connection.authentication && authResult && connection.authentication.accessToken === authResult.accessToken;
|
|
46
|
+
const {
|
|
47
|
+
accessToken,
|
|
48
|
+
entity
|
|
49
|
+
} = authResult || {};
|
|
50
|
+
if (accessToken && event === 'login') {
|
|
51
|
+
const validUcan = await symbolUcan.validateUcan(accessToken).catch(err => {
|
|
52
|
+
console.log('Could not validate ucan in connection: ', err.message);
|
|
53
|
+
const errObj = {
|
|
54
|
+
code: 0,
|
|
55
|
+
message: 'Unknown Issue Validating Ucan'
|
|
56
|
+
};
|
|
57
|
+
if (err.message.indexOf('Expired.') > -1) {
|
|
58
|
+
errObj.code = 1;
|
|
59
|
+
errObj.message = 'Expired Ucan';
|
|
60
|
+
}
|
|
61
|
+
throw new Error(errObj.message);
|
|
62
|
+
});
|
|
63
|
+
const {
|
|
64
|
+
payload: {
|
|
65
|
+
exp
|
|
66
|
+
}
|
|
67
|
+
} = validUcan || {
|
|
68
|
+
payload: {
|
|
69
|
+
exp: 0
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
// The time (in ms) until the token expires
|
|
73
|
+
const duration = exp * 1000 - Date.now();
|
|
74
|
+
// This may have to be a `logout` event but right now we don't want
|
|
75
|
+
// the whole context object lingering around until the timer is gone
|
|
76
|
+
const timer = lt__default["default"].setTimeout(() => this.app.emit('disconnect', connection), duration);
|
|
77
|
+
lt__default["default"].clearTimeout(this.expirationTimers.get(connection));
|
|
78
|
+
this.expirationTimers.set(connection, timer);
|
|
79
|
+
connection.authentication = {
|
|
80
|
+
strategy: this.name,
|
|
81
|
+
accessToken
|
|
82
|
+
};
|
|
83
|
+
} else if (event === 'disconnect' || isValidLogout) {
|
|
84
|
+
const {
|
|
85
|
+
entity
|
|
86
|
+
} = this.configuration;
|
|
87
|
+
delete connection[entity];
|
|
88
|
+
delete connection.authentication;
|
|
89
|
+
lt__default["default"].clearTimeout(this.expirationTimers.get(connection));
|
|
90
|
+
this.expirationTimers.delete(connection);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
verifyConfiguration() {
|
|
94
|
+
const allowedKeys = ['entity', 'entityId', 'service', 'header', 'schemes', 'audience'];
|
|
95
|
+
for (const key of Object.keys(this.configuration)) {
|
|
96
|
+
if (!allowedKeys.includes(key)) {
|
|
97
|
+
throw new Error(`Invalid ucanStrategy option 'authentication.${this.name}.${key}'. Did you mean to set it in 'authentication.jwtOptions'?`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (typeof this.configuration.header !== 'string') {
|
|
101
|
+
throw new Error(`The 'header' option for the ${this.name} strategy must be a string`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// eslint-disable-next-line no-unused-vars
|
|
105
|
+
async getEntityQuery(_params) {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Return the entity for a given id
|
|
110
|
+
* @param id The id to use
|
|
111
|
+
* @param params Service call parameters
|
|
112
|
+
*/
|
|
113
|
+
async getEntity(id, params) {
|
|
114
|
+
const entityService = this.entityService;
|
|
115
|
+
const {
|
|
116
|
+
entity
|
|
117
|
+
} = this.configuration;
|
|
118
|
+
if (entityService === null) {
|
|
119
|
+
throw new NotAuthError$1('Could not find entity service');
|
|
120
|
+
}
|
|
121
|
+
const query = await this.getEntityQuery(params);
|
|
122
|
+
const getParams = Object.assign({}, symbolUcan._unset(params, 'provider'), {
|
|
123
|
+
query
|
|
124
|
+
});
|
|
125
|
+
const result = await entityService.get(id, getParams);
|
|
126
|
+
if (!params.provider) {
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
return entityService.get(id, {
|
|
130
|
+
...params,
|
|
131
|
+
[entity]: result
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async getEntityId(authResult, _params) {
|
|
135
|
+
let {
|
|
136
|
+
query,
|
|
137
|
+
loginId
|
|
138
|
+
} = _params;
|
|
139
|
+
if (loginId) return loginId;else {
|
|
140
|
+
var _this$app;
|
|
141
|
+
const {
|
|
142
|
+
service,
|
|
143
|
+
core_path = 'core'
|
|
144
|
+
} = this.configuration;
|
|
145
|
+
const pms = {
|
|
146
|
+
query: {
|
|
147
|
+
...query,
|
|
148
|
+
$limit: 1
|
|
149
|
+
},
|
|
150
|
+
[core_path]: {
|
|
151
|
+
skipJoins: true,
|
|
152
|
+
..._params[core_path]
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const entities = await ((_this$app = this.app) == null ? void 0 : _this$app.service(service).find({
|
|
156
|
+
...pms,
|
|
157
|
+
skipJoins: true,
|
|
158
|
+
skip_hooks: true,
|
|
159
|
+
admin_pass: true
|
|
160
|
+
}));
|
|
161
|
+
if (entities.total) return entities.data[0]._id;else throw new NotAuthError$1('Could not find login associated with this ucan');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async authenticate(authentication, params) {
|
|
165
|
+
let {
|
|
166
|
+
accessToken,
|
|
167
|
+
loginId,
|
|
168
|
+
ucan
|
|
169
|
+
} = authentication;
|
|
170
|
+
const {
|
|
171
|
+
entity,
|
|
172
|
+
core_path
|
|
173
|
+
} = this.configuration;
|
|
174
|
+
if (!accessToken) {
|
|
175
|
+
if (ucan) accessToken = symbolUcan.ucanToken(ucan);else throw new NotAuthError$1('Error generating ucan');
|
|
176
|
+
// } else throw new NotAuthenticated('No access token');
|
|
177
|
+
}
|
|
178
|
+
//
|
|
179
|
+
// await verifyUcan(accessToken, {audience: ucan_audience || params.ucan_aud, requiredCapabilities})
|
|
180
|
+
// .catch(err => {
|
|
181
|
+
// console.error('error verifying ucan', err);
|
|
182
|
+
// throw new NotAuthenticated('Could not verify ucan: ' + err.message);
|
|
183
|
+
// });
|
|
184
|
+
const decodedUcan = await symbolUcan.validateUcan(accessToken).catch(err => {
|
|
185
|
+
console.log('Could not validate ucan during authentication: ', err.message);
|
|
186
|
+
const errObj = {
|
|
187
|
+
code: 0,
|
|
188
|
+
message: 'Unknown Issue Validating Ucan'
|
|
189
|
+
};
|
|
190
|
+
if (err.message.indexOf('Expired.') > -1) {
|
|
191
|
+
errObj.code = 1;
|
|
192
|
+
errObj.message = 'Expired Ucan';
|
|
193
|
+
}
|
|
194
|
+
throw new Error(errObj.message);
|
|
195
|
+
});
|
|
196
|
+
const result = {
|
|
197
|
+
accessToken,
|
|
198
|
+
authentication: {
|
|
199
|
+
strategy: 'jwt',
|
|
200
|
+
accessToken
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
if (entity === null) {
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
let value;
|
|
207
|
+
const coreEntity = symbolUcan._get(params, [core_path, entity]);
|
|
208
|
+
if (!coreEntity) {
|
|
209
|
+
const entityId = await this.getEntityId(result, {
|
|
210
|
+
...params,
|
|
211
|
+
loginId,
|
|
212
|
+
query: {
|
|
213
|
+
did: decodedUcan == null ? void 0 : decodedUcan.payload.aud
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
value = await this.getEntity(entityId, params);
|
|
217
|
+
} else value = coreEntity;
|
|
218
|
+
return {
|
|
219
|
+
...result,
|
|
220
|
+
[entity]: value
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
async parse(req) {
|
|
224
|
+
const {
|
|
225
|
+
header,
|
|
226
|
+
schemes
|
|
227
|
+
} = this.configuration;
|
|
228
|
+
const headerValue = req.headers && req.headers[header.toLowerCase()];
|
|
229
|
+
if (!headerValue || typeof headerValue !== 'string') {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const [, scheme, schemeValue] = headerValue.match(SPLIT_HEADER) || [];
|
|
233
|
+
const hasScheme = scheme && schemes.some(current => new RegExp(current, 'i').test(scheme));
|
|
234
|
+
if (scheme && !hasScheme) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
strategy: this.name,
|
|
239
|
+
accessToken: hasScheme ? schemeValue : headerValue
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
class NotAuthError extends Error {
|
|
245
|
+
constructor(message) {
|
|
246
|
+
super(message);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
class AuthService extends authentication.AuthenticationService {
|
|
250
|
+
constructor(app, configKey = 'authentication', opts = {}) {
|
|
251
|
+
const {
|
|
252
|
+
NotAuthenticated,
|
|
253
|
+
...rest
|
|
254
|
+
} = opts;
|
|
255
|
+
super(app, configKey, rest);
|
|
256
|
+
this.options = void 0;
|
|
257
|
+
this.app = app;
|
|
258
|
+
this.options = {
|
|
259
|
+
NotAuthenticated
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async create(data, params) {
|
|
263
|
+
var _this$options, _params;
|
|
264
|
+
const NotAuth = ((_this$options = this.options) == null ? void 0 : _this$options.NotAuthenticated) || NotAuthError;
|
|
265
|
+
const {
|
|
266
|
+
entity,
|
|
267
|
+
service,
|
|
268
|
+
ucan_path = 'ucan'
|
|
269
|
+
} = this.app.get('authentication');
|
|
270
|
+
const authStrategies = ((_params = params) == null ? void 0 : _params.authStrategies) || this.configuration.authStrategies;
|
|
271
|
+
if (!params) params = {};
|
|
272
|
+
if (!authStrategies.length) {
|
|
273
|
+
throw new NotAuth('No authentication strategies allowed for creating a JWT (`authStrategies`)');
|
|
274
|
+
}
|
|
275
|
+
const authResult = await this.authenticate(data, params, ...authStrategies).catch(err => {
|
|
276
|
+
throw new Error(err.message);
|
|
277
|
+
});
|
|
278
|
+
if (authResult.accessToken) {
|
|
279
|
+
return authResult;
|
|
280
|
+
}
|
|
281
|
+
const did = data.did || symbolUcan._get(authResult, [entity, 'did']);
|
|
282
|
+
let ucan = data.ucan || symbolUcan._get(authResult, [entity, 'ucan']);
|
|
283
|
+
if (!did) throw new Error('No did audience provided');
|
|
284
|
+
if (!ucan) throw new Error('No ucan provided to authentication call');
|
|
285
|
+
// const {secret} = this.configuration;
|
|
286
|
+
const validatedUcan = await symbolUcan.validateUcan(ucan).catch(err => {
|
|
287
|
+
console.log('Could not validate ucan creating authentication: ', err.message);
|
|
288
|
+
const errObj = {
|
|
289
|
+
code: 0,
|
|
290
|
+
message: 'Unknown Issue Validating Ucan'
|
|
291
|
+
};
|
|
292
|
+
if (err.message.indexOf('Expired.') > -1) {
|
|
293
|
+
errObj.code = 1;
|
|
294
|
+
errObj.message = 'Expired Ucan';
|
|
295
|
+
}
|
|
296
|
+
console.warn('Could not validate ucan creating authentication', ucan, errObj.message);
|
|
297
|
+
return null;
|
|
298
|
+
});
|
|
299
|
+
if (!validatedUcan) {
|
|
300
|
+
const parsed = symbolUcan.parseUcan(ucan);
|
|
301
|
+
let {
|
|
302
|
+
secret
|
|
303
|
+
} = this.app.get('authentication');
|
|
304
|
+
const issuer = symbolUcan.encodeKeyPair({
|
|
305
|
+
secretKey: secret
|
|
306
|
+
});
|
|
307
|
+
ucan = await symbolUcan.buildUcan({
|
|
308
|
+
audience: parsed.payload.aud,
|
|
309
|
+
issuer,
|
|
310
|
+
lifetimeInSeconds: 60 * 60 * 24 * 60,
|
|
311
|
+
capabilities: parsed.payload.att
|
|
312
|
+
});
|
|
313
|
+
params.admin_pass = true;
|
|
314
|
+
await this.app.service(service).patch(symbolUcan._get(authResult, [entity, '_id']), {
|
|
315
|
+
[ucan_path]: symbolUcan.ucanToken(ucan)
|
|
316
|
+
}, {
|
|
317
|
+
...params
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const accessToken = symbolUcan.ucanToken(ucan);
|
|
321
|
+
return {
|
|
322
|
+
accessToken,
|
|
323
|
+
...authResult,
|
|
324
|
+
authentication: {
|
|
325
|
+
...authResult.authentication,
|
|
326
|
+
payload: accessToken
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
class CoreCall {
|
|
333
|
+
constructor(service, context, coreOptions) {
|
|
334
|
+
var _context$params;
|
|
335
|
+
this.context = void 0;
|
|
336
|
+
this.service = void 0;
|
|
337
|
+
this.core = void 0;
|
|
338
|
+
this.entity = void 0;
|
|
339
|
+
this.service = service;
|
|
340
|
+
this.context = context;
|
|
341
|
+
const entity = (context.app.get('authentication') || {
|
|
342
|
+
entity: 'login'
|
|
343
|
+
}).entity || 'login';
|
|
344
|
+
this.entity = entity;
|
|
345
|
+
const core = ((_context$params = context.params) == null ? void 0 : _context$params.core) || {};
|
|
346
|
+
if (!core[entity]) core[entity] = context.params[entity];
|
|
347
|
+
this.core = {
|
|
348
|
+
...core,
|
|
349
|
+
...coreOptions
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
async get(id, params = {}) {
|
|
353
|
+
var _this$context$app;
|
|
354
|
+
const {
|
|
355
|
+
core_path
|
|
356
|
+
} = this.context.app.get('authentication');
|
|
357
|
+
return (_this$context$app = this.context.app) == null ? void 0 : _this$context$app.service(this.service).get(id, {
|
|
358
|
+
...params,
|
|
359
|
+
[this.entity]: params[this.entity],
|
|
360
|
+
...{
|
|
361
|
+
[core_path]: this.core
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
async find(params = {}) {
|
|
366
|
+
var _this$context$app2;
|
|
367
|
+
const {
|
|
368
|
+
core_path
|
|
369
|
+
} = this.context.app.get('authentication');
|
|
370
|
+
return (_this$context$app2 = this.context.app) == null ? void 0 : _this$context$app2.service(this.service).find({
|
|
371
|
+
...params,
|
|
372
|
+
[this.entity]: params[this.entity],
|
|
373
|
+
skip_hooks: true,
|
|
374
|
+
admin_pass: true,
|
|
375
|
+
...{
|
|
376
|
+
[core_path]: this.core
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
async create(data, params = {}) {
|
|
381
|
+
var _this$context$app3;
|
|
382
|
+
const {
|
|
383
|
+
core_path
|
|
384
|
+
} = this.context.app.get('authentication');
|
|
385
|
+
return (_this$context$app3 = this.context.app) == null ? void 0 : _this$context$app3.service(this.service).create(data, {
|
|
386
|
+
...params,
|
|
387
|
+
[this.entity]: params[this.entity],
|
|
388
|
+
...{
|
|
389
|
+
[core_path]: this.core
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
async patch(id, data, params = {}) {
|
|
394
|
+
var _this$context$app4;
|
|
395
|
+
const {
|
|
396
|
+
core_path
|
|
397
|
+
} = this.context.app.get('authentication');
|
|
398
|
+
return (_this$context$app4 = this.context.app) == null ? void 0 : _this$context$app4.service(this.service).patch(id, data, {
|
|
399
|
+
...params,
|
|
400
|
+
[this.entity]: params[this.entity],
|
|
401
|
+
...{
|
|
402
|
+
[core_path]: this.core
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
async update(id, data, params = {}) {
|
|
407
|
+
var _this$context$app5;
|
|
408
|
+
const {
|
|
409
|
+
core_path
|
|
410
|
+
} = this.context.app.get('authentication');
|
|
411
|
+
return (_this$context$app5 = this.context.app) == null ? void 0 : _this$context$app5.service(this.service).update(id, data, {
|
|
412
|
+
...params,
|
|
413
|
+
[this.entity]: params[this.entity],
|
|
414
|
+
...{
|
|
415
|
+
[core_path]: this.core
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
async remove(id, params = {}) {
|
|
420
|
+
var _this$context$app6;
|
|
421
|
+
const {
|
|
422
|
+
core_path
|
|
423
|
+
} = this.context.app.get('authentication');
|
|
424
|
+
return (_this$context$app6 = this.context.app) == null ? void 0 : _this$context$app6.service(this.service).remove(id, {
|
|
425
|
+
...params,
|
|
426
|
+
[this.entity]: params[this.entity],
|
|
427
|
+
...{
|
|
428
|
+
[core_path]: this.core
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
async _get(id, params = {}) {
|
|
433
|
+
var _this$context$app7;
|
|
434
|
+
const {
|
|
435
|
+
core_path
|
|
436
|
+
} = this.context.app.get('authentication');
|
|
437
|
+
return (_this$context$app7 = this.context.app) == null ? void 0 : _this$context$app7.service(this.service)._get(id, {
|
|
438
|
+
...params,
|
|
439
|
+
[this.entity]: params[this.entity],
|
|
440
|
+
...{
|
|
441
|
+
[core_path]: this.core
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
async _find(params = {}) {
|
|
446
|
+
var _this$context$app8;
|
|
447
|
+
const {
|
|
448
|
+
core_path
|
|
449
|
+
} = this.context.app.get('authentication');
|
|
450
|
+
return (_this$context$app8 = this.context.app) == null ? void 0 : _this$context$app8.service(this.service)._find({
|
|
451
|
+
...params,
|
|
452
|
+
[this.entity]: params[this.entity],
|
|
453
|
+
...{
|
|
454
|
+
[core_path]: this.core
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
async _create(data, params = {}) {
|
|
459
|
+
var _this$context$app9;
|
|
460
|
+
const {
|
|
461
|
+
core_path
|
|
462
|
+
} = this.context.app.get('authentication');
|
|
463
|
+
return (_this$context$app9 = this.context.app) == null ? void 0 : _this$context$app9.service(this.service)._create(data, {
|
|
464
|
+
...params,
|
|
465
|
+
[this.entity]: params[this.entity],
|
|
466
|
+
...{
|
|
467
|
+
[core_path]: this.core
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
async _patch(id, data, params = {}) {
|
|
472
|
+
var _this$context$app10;
|
|
473
|
+
const {
|
|
474
|
+
core_path
|
|
475
|
+
} = this.context.app.get('authentication');
|
|
476
|
+
return (_this$context$app10 = this.context.app) == null ? void 0 : _this$context$app10.service(this.service)._patch(id, data, {
|
|
477
|
+
...params,
|
|
478
|
+
[this.entity]: params[this.entity],
|
|
479
|
+
...{
|
|
480
|
+
[core_path]: this.core
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
async _update(id, data, params = {}) {
|
|
485
|
+
var _this$context$app11;
|
|
486
|
+
const {
|
|
487
|
+
core_path
|
|
488
|
+
} = this.context.app.get('authentication');
|
|
489
|
+
return (_this$context$app11 = this.context.app) == null ? void 0 : _this$context$app11.service(this.service)._update(id, data, {
|
|
490
|
+
...params,
|
|
491
|
+
[this.entity]: params[this.entity],
|
|
492
|
+
...{
|
|
493
|
+
[core_path]: this.core
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
async _remove(id, params = {}) {
|
|
498
|
+
var _this$context$app12;
|
|
499
|
+
const {
|
|
500
|
+
core_path
|
|
501
|
+
} = this.context.app.get('authentication');
|
|
502
|
+
return (_this$context$app12 = this.context.app) == null ? void 0 : _this$context$app12.service(this.service)._remove(id, {
|
|
503
|
+
...params,
|
|
504
|
+
[this.entity]: params[this.entity],
|
|
505
|
+
...{
|
|
506
|
+
[core_path]: this.core
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const existsPath = '_exists';
|
|
513
|
+
const getExists = context => {
|
|
514
|
+
const path = context.app.get('existsPath') || existsPath;
|
|
515
|
+
return symbolUcan._get(context.params, `core.${path}.${context.path}.${context.id}`) || undefined;
|
|
516
|
+
};
|
|
517
|
+
const loadExists = async (context, options) => {
|
|
518
|
+
let ex = getExists(context);
|
|
519
|
+
if (!ex && context.id) {
|
|
520
|
+
ex = await new CoreCall(context.path, context, {
|
|
521
|
+
skipJoins: (options == null ? void 0 : options.skipJoins) !== false
|
|
522
|
+
}).get(context.id, {
|
|
523
|
+
exists_check: true,
|
|
524
|
+
admin_pass: true,
|
|
525
|
+
skip_hooks: true,
|
|
526
|
+
...((options == null ? void 0 : options.params) || {})
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return ex;
|
|
530
|
+
};
|
|
531
|
+
const setExists = (context, val) => {
|
|
532
|
+
const path = context.app.get('existsPath') || existsPath;
|
|
533
|
+
context.params = symbolUcan._set(context.params, `core.${path}.${context.path}.${(val == null ? void 0 : val._id) || context.id}`, val);
|
|
534
|
+
return context;
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
const SUPERUSER = '*';
|
|
538
|
+
const anyAuth = '*';
|
|
539
|
+
const noThrow = '$';
|
|
540
|
+
const noThrowAuth = async context => {
|
|
541
|
+
const config = context.app.get('authentication');
|
|
542
|
+
const entity = symbolUcan._get(context, ['auth', config.entity]);
|
|
543
|
+
if (entity) {
|
|
544
|
+
context = symbolUcan._set(context, [config.core_path, config.entity], entity);
|
|
545
|
+
}
|
|
546
|
+
try {
|
|
547
|
+
context = await authentication.authenticate('jwt')(context).catch(() => {
|
|
548
|
+
return context;
|
|
549
|
+
});
|
|
550
|
+
} catch (e) {
|
|
551
|
+
return context;
|
|
552
|
+
}
|
|
553
|
+
return context;
|
|
554
|
+
};
|
|
555
|
+
const bareAuth = async context => {
|
|
556
|
+
const config = context.app.get('authentication');
|
|
557
|
+
const entity = symbolUcan._get(context, ['auth', config.entity]);
|
|
558
|
+
if (entity) context = symbolUcan._set(context, [config.core_path, config.entity], entity);
|
|
559
|
+
return authentication.authenticate('jwt')(context);
|
|
560
|
+
};
|
|
561
|
+
const verifyOne = async (ucan, options, log) => {
|
|
562
|
+
try {
|
|
563
|
+
var _v;
|
|
564
|
+
let v = await symbolUcan.verifyUcan(ucan, options);
|
|
565
|
+
if (!((_v = v) != null && _v.ok) && options.requiredCapabilities) {
|
|
566
|
+
const newCapabilities = options.requiredCapabilities.map(a => {
|
|
567
|
+
if (a.capability.can !== SUPERUSER) a.capability.can.segments = ['*'];
|
|
568
|
+
return a;
|
|
569
|
+
});
|
|
570
|
+
if (log) console.log('set new req capabilities', newCapabilities, symbolUcan.parseUcan(ucan));
|
|
571
|
+
v = await symbolUcan.verifyUcan(ucan, {
|
|
572
|
+
...options,
|
|
573
|
+
requiredCapabilities: newCapabilities
|
|
574
|
+
});
|
|
575
|
+
if (log) console.log('Second verification result:', v);
|
|
576
|
+
}
|
|
577
|
+
return v;
|
|
578
|
+
} catch (e) {
|
|
579
|
+
return {
|
|
580
|
+
ok: false,
|
|
581
|
+
err: [e.message]
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
const orVerifyLoop = async (arr, log) => {
|
|
586
|
+
let v = {
|
|
587
|
+
ok: false,
|
|
588
|
+
value: []
|
|
589
|
+
};
|
|
590
|
+
try {
|
|
591
|
+
for (const i in arr) {
|
|
592
|
+
var _v2;
|
|
593
|
+
if (log) console.log('or verify loop', arr[i], symbolUcan.parseUcan(arr[i].ucan));
|
|
594
|
+
if (!((_v2 = v) != null && _v2.ok)) {
|
|
595
|
+
const {
|
|
596
|
+
ucan,
|
|
597
|
+
...options
|
|
598
|
+
} = arr[i];
|
|
599
|
+
v = await verifyOne(ucan, options, log);
|
|
600
|
+
if (log) console.log('got in verify loop', v);
|
|
601
|
+
} else break;
|
|
602
|
+
}
|
|
603
|
+
return v;
|
|
604
|
+
} catch (e) {
|
|
605
|
+
return {
|
|
606
|
+
ok: false,
|
|
607
|
+
err: [e.message]
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
const verifyAgainstReqs = (reqs, config, options) => {
|
|
612
|
+
return async context => {
|
|
613
|
+
var _v3;
|
|
614
|
+
const log = options == null ? void 0 : options.log;
|
|
615
|
+
const ucan = symbolUcan._get(context.params, config.client_ucan);
|
|
616
|
+
const audience = (options == null ? void 0 : options.audience) || symbolUcan._get(context.params, config.ucan_aud);
|
|
617
|
+
if (log) console.log('verify against reqs', reqs);
|
|
618
|
+
let vMethod;
|
|
619
|
+
const or = (options == null ? void 0 : options.or) || [];
|
|
620
|
+
if (ucan && (or === '*' || or.includes(context.method))) vMethod = (uc, methodOpts) => orVerifyLoop((reqs || []).map(a => {
|
|
621
|
+
return {
|
|
622
|
+
ucan: uc || ucan,
|
|
623
|
+
audience: (methodOpts == null ? void 0 : methodOpts.aud) || audience,
|
|
624
|
+
requiredCapabilities: [a]
|
|
625
|
+
};
|
|
626
|
+
}), log);else vMethod = (uc, methodOpts) => verifyOne(uc || ucan, {
|
|
627
|
+
audience: (methodOpts == null ? void 0 : methodOpts.aud) || audience,
|
|
628
|
+
requiredCapabilities: reqs
|
|
629
|
+
}, log);
|
|
630
|
+
let v = await vMethod();
|
|
631
|
+
if (log) console.log('first verify try', v);
|
|
632
|
+
if ((_v3 = v) != null && _v3.ok) return v;
|
|
633
|
+
const cs = ((options == null ? void 0 : options.cap_subjects) || []).filter(a => !!a);
|
|
634
|
+
if (log) console.log('check cap_subjects', cs);
|
|
635
|
+
if (cs) {
|
|
636
|
+
const configuration = (config == null ? void 0 : config.loginConfig) || context.app.get('authentication');
|
|
637
|
+
const loginCheckId = String(symbolUcan._get(context.params, `${configuration.entity}._id` || ''));
|
|
638
|
+
const caps = await new CoreCall(configuration.capability_service || 'caps', context).find({
|
|
639
|
+
query: {
|
|
640
|
+
$limit: cs.length,
|
|
641
|
+
subject: {
|
|
642
|
+
$in: cs
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
skip_hooks: true,
|
|
646
|
+
admin_pass: true
|
|
647
|
+
}).catch(err => console.log(`Error finding caps in ucan auth: ${err.message}`));
|
|
648
|
+
if (log) console.log('caps', caps);
|
|
649
|
+
if (caps != null && caps.data) {
|
|
650
|
+
for (const cap of caps.data) {
|
|
651
|
+
for (const k in cap.caps || {}) {
|
|
652
|
+
if (log) console.log('check cap', k, cap.caps[k].logins, loginCheckId);
|
|
653
|
+
if ((cap.caps[k].logins || []).map(a => String(a)).includes(loginCheckId)) {
|
|
654
|
+
var _v4;
|
|
655
|
+
try {
|
|
656
|
+
const ucanString = symbolUcan.ucanToken(cap.caps[k].ucan);
|
|
657
|
+
if (log) console.log('got ucan string', ucanString);
|
|
658
|
+
if (ucanString) {
|
|
659
|
+
v = await vMethod(ucanString, {
|
|
660
|
+
aud: cap.did
|
|
661
|
+
});
|
|
662
|
+
if (log) console.log('tried v on cap', v);
|
|
663
|
+
}
|
|
664
|
+
} catch (e) {
|
|
665
|
+
console.log(`Error verifying ucan from cap: ${cap._id}. Err:${e.message}`);
|
|
666
|
+
}
|
|
667
|
+
if (options != null && options.log) console.log('tried v on cap', v);
|
|
668
|
+
if ((_v4 = v) != null && _v4.ok) return v;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return v;
|
|
675
|
+
};
|
|
676
|
+
};
|
|
677
|
+
const modelCapabilities = (reqs, config) => {
|
|
678
|
+
const rootIssuer = symbolUcan.encodeKeyPair({
|
|
679
|
+
secretKey: config.secret
|
|
680
|
+
}).did();
|
|
681
|
+
if (!Array.isArray(reqs)) return [];
|
|
682
|
+
return reqs.map(a => {
|
|
683
|
+
return {
|
|
684
|
+
capability: Array.isArray(a) ? symbolUcan.genCapability({
|
|
685
|
+
with: {
|
|
686
|
+
scheme: config.defaultScheme,
|
|
687
|
+
hierPart: config.defaultHierPart
|
|
688
|
+
},
|
|
689
|
+
can: {
|
|
690
|
+
namespace: a[0],
|
|
691
|
+
segments: typeof a[1] === 'string' ? [a[1]] : a[1]
|
|
692
|
+
}
|
|
693
|
+
}, config) : symbolUcan.genCapability(a, config),
|
|
694
|
+
rootIssuer
|
|
695
|
+
};
|
|
696
|
+
});
|
|
697
|
+
};
|
|
698
|
+
const checkUcan = (requiredCapabilities, options) => {
|
|
699
|
+
return async context => {
|
|
700
|
+
var _v5;
|
|
701
|
+
const configuration = (options == null ? void 0 : options.loginConfig) || context.app.get('authentication');
|
|
702
|
+
let v = {
|
|
703
|
+
ok: false,
|
|
704
|
+
value: []
|
|
705
|
+
};
|
|
706
|
+
const reqs = modelCapabilities(requiredCapabilities, configuration);
|
|
707
|
+
if (reqs.length) {
|
|
708
|
+
v = await verifyAgainstReqs(reqs, configuration, options)(context);
|
|
709
|
+
/** if the anyAuth setting is used along with specialChange, a user could get through to this point despite not being authenticated, so this step does not allow a pass for anyAuth setting even though no requiredCapabilities are present - because it was intended to throw if not authenticated unless special change conditions are met */
|
|
710
|
+
} else if (requiredCapabilities !== '*') v.ok = true;
|
|
711
|
+
if ((_v5 = v) != null && _v5.ok) {
|
|
712
|
+
context.params.authenticated = true;
|
|
713
|
+
context.params.canU = true;
|
|
714
|
+
return context;
|
|
715
|
+
} else {
|
|
716
|
+
var _v6;
|
|
717
|
+
// if (!v?.ok) {
|
|
718
|
+
// let hasSplitNamespace = false;
|
|
719
|
+
// const reducedReqs: Array<RequiredCapability> = [];
|
|
720
|
+
// reqs.forEach((req, i) => {
|
|
721
|
+
// const splt = (_get<RequiredCapability, string>(req, 'capability.can.namespace') || '').split(':')
|
|
722
|
+
// if (splt[1]) {
|
|
723
|
+
// req = _set(req, 'capability.can.namespace', splt[0]);
|
|
724
|
+
// hasSplitNamespace = true;
|
|
725
|
+
// }
|
|
726
|
+
// reducedReqs.push(req)
|
|
727
|
+
// })
|
|
728
|
+
// if (hasSplitNamespace) v = await verifyAgainstReqs(reqs, configuration as VerifyConfig, options)(context);
|
|
729
|
+
// }
|
|
730
|
+
if (options != null && options.log) console.log('checking special change', options == null ? void 0 : options.specialChange);
|
|
731
|
+
if (options != null && options.specialChange) {
|
|
732
|
+
if (options.specialChange === anyAuth) {
|
|
733
|
+
context.params.canU = true;
|
|
734
|
+
return context;
|
|
735
|
+
} else if (Array.isArray(options.specialChange)) {
|
|
736
|
+
if (['create', 'patch', 'update'].includes(context.method)) {
|
|
737
|
+
if (Array.isArray(context.data)) throw new Error('No multi data allowed with special change');
|
|
738
|
+
for (const k in context.data || {}) {
|
|
739
|
+
if (['$set', '$unset', '$addToSet', '$pull', '$push'].includes(k)) {
|
|
740
|
+
for (const sk in context.data[k] || {}) {
|
|
741
|
+
if (!options.specialChange.includes(sk)) {
|
|
742
|
+
const spl = sk.split('.');
|
|
743
|
+
if (spl.length === 1) delete context.data[k][sk];else if (!options.specialChange.includes(spl[0])) delete context.data[k][sk];
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
} else if (!options.specialChange.includes(k)) delete context.data[k];
|
|
747
|
+
}
|
|
748
|
+
context.params.canU = true;
|
|
749
|
+
return context;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if ((_v6 = v) != null && _v6.ok) {
|
|
754
|
+
context.params.authenticated = true;
|
|
755
|
+
context.params.canU = true;
|
|
756
|
+
return context;
|
|
757
|
+
} else {
|
|
758
|
+
var _v7;
|
|
759
|
+
//If creator pass enabled, check to see if the auth login is the creator of the record
|
|
760
|
+
const {
|
|
761
|
+
loginPass
|
|
762
|
+
} = options || {
|
|
763
|
+
loginPass: [[['*'], ['nonExistentMethod']]]
|
|
764
|
+
};
|
|
765
|
+
if (loginPass != null && loginPass.length) {
|
|
766
|
+
//object of scrubbed data object for pass that includes only limited access or full context.data object if no limits were present
|
|
767
|
+
let scrubbedData = {};
|
|
768
|
+
//scruData defaults to true - is only set to false
|
|
769
|
+
let scrubData = true;
|
|
770
|
+
const checkLoginPass = async lpass => {
|
|
771
|
+
let methodsOnly = [];
|
|
772
|
+
const allMethods = lpass[1] === '*';
|
|
773
|
+
let methodIdx = -1;
|
|
774
|
+
if (allMethods) methodIdx = 0;else {
|
|
775
|
+
//separate out any field specific methods e.g. patch/name,avatar
|
|
776
|
+
methodsOnly = lpass[1].map(a => a.split('/')[0]);
|
|
777
|
+
methodIdx = methodsOnly.indexOf(context.method);
|
|
778
|
+
}
|
|
779
|
+
/**ensure loginPass is allowed for this method*/
|
|
780
|
+
if (methodIdx > -1) {
|
|
781
|
+
/**retrieve existing record to check ids for login id*/
|
|
782
|
+
const existing = await loadExists(context, {
|
|
783
|
+
params: options == null ? void 0 : options.existingParams
|
|
784
|
+
});
|
|
785
|
+
let loginOk = false;
|
|
786
|
+
/** function for comparing record login id with context login*/
|
|
787
|
+
const checkLogin = (recordLoginPassId, loginIdPath = '_id') => {
|
|
788
|
+
const loginCheckId = symbolUcan._get(context.params, `${configuration.entity}.${loginIdPath}`);
|
|
789
|
+
/**Make sure both are present to avoid pass on undefined*/
|
|
790
|
+
if (loginCheckId && recordLoginPassId) {
|
|
791
|
+
/** change login path result to array no matter what */
|
|
792
|
+
const checkArr = Array.isArray(loginCheckId) ? loginCheckId.map(a => String(a)) : [String(loginCheckId)];
|
|
793
|
+
if (Array.isArray(recordLoginPassId)) {
|
|
794
|
+
/**loop through to see if there is a match present use for loops for performance instead of some*/
|
|
795
|
+
for (let i = 0; i < checkArr.length; i++) {
|
|
796
|
+
const checkId = String(checkArr[i]);
|
|
797
|
+
for (let rl = 0; rl < recordLoginPassId.length;) {
|
|
798
|
+
const rlId = String(recordLoginPassId[rl]);
|
|
799
|
+
if (rlId === checkId) loginOk = true;else rl++;
|
|
800
|
+
}
|
|
801
|
+
if (loginOk) return;
|
|
802
|
+
}
|
|
803
|
+
} else if (checkArr.includes(String(recordLoginPassId))) {
|
|
804
|
+
return loginOk = true;
|
|
805
|
+
}
|
|
806
|
+
} else return;
|
|
807
|
+
};
|
|
808
|
+
if (existing) {
|
|
809
|
+
context = setExists(context, existing);
|
|
810
|
+
for (const passPath of lpass[0] || []) {
|
|
811
|
+
const spl = String(passPath).split('/');
|
|
812
|
+
if (spl[0].includes('*')) {
|
|
813
|
+
const spl2 = spl[0].split('*');
|
|
814
|
+
const obj = symbolUcan._get(existing, spl2[0]);
|
|
815
|
+
if (obj && typeof obj === 'object') {
|
|
816
|
+
if (Array.isArray(obj)) {
|
|
817
|
+
/** IF array, iterate through array and check the sub-path */
|
|
818
|
+
for (const o of obj) {
|
|
819
|
+
checkLogin(symbolUcan._get(o, spl2[1]), spl[1] || '_id');
|
|
820
|
+
if (loginOk) break;
|
|
821
|
+
}
|
|
822
|
+
} else {
|
|
823
|
+
/** IF object, iterate through object and check the sub-path */
|
|
824
|
+
for (const k in obj) {
|
|
825
|
+
checkLogin(symbolUcan._get(obj, `${k}.${spl2[1]}`), spl[1] || '_id');
|
|
826
|
+
if (loginOk) break;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
} else checkLogin(symbolUcan._get(existing, spl[0]), spl[1] || '_id');
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
if (loginOk) {
|
|
834
|
+
v.ok = true;
|
|
835
|
+
/**loginPass is true - but check for granular field permissions such as patch/owner,color,status that imply limited permission*/
|
|
836
|
+
//TODO: possibly a throw option here. If loginPass is ok, it will go forward, but could send an empty or modified patch object
|
|
837
|
+
if (lpass[1] !== '*' && !['find', 'get', 'remove'].some(a => lpass[1].includes(a))) {
|
|
838
|
+
const currentMethod = allMethods ? '*' : lpass[1][methodIdx];
|
|
839
|
+
const splitMethod = currentMethod.split('/')[0];
|
|
840
|
+
//check if current method contains a split '/' signaling limited permission check
|
|
841
|
+
if (splitMethod !== currentMethod) {
|
|
842
|
+
//get an array of the allowed fields
|
|
843
|
+
const fields = currentMethod.split('/').slice(1).join('').split(',') || [];
|
|
844
|
+
for (const field of fields) {
|
|
845
|
+
const topLevel = symbolUcan._get(context.data, field);
|
|
846
|
+
if (topLevel) scrubbedData = symbolUcan._set(scrubbedData, field, topLevel);else {
|
|
847
|
+
for (const operator of ['$addToSet', '$pull']) {
|
|
848
|
+
const operatorLevel = symbolUcan._get(context.data, `${operator}.${field}`);
|
|
849
|
+
if (operatorLevel) scrubbedData = symbolUcan._set(scrubbedData, `${operator}.${field}`, operatorLevel);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
} else scrubData = false;
|
|
854
|
+
} else scrubData = false;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
for await (const lpass of loginPass) {
|
|
859
|
+
if (scrubData) await checkLoginPass(lpass);else break;
|
|
860
|
+
}
|
|
861
|
+
if (scrubData) context = symbolUcan._set(context, 'data', scrubbedData);
|
|
862
|
+
}
|
|
863
|
+
if ((_v7 = v) != null && _v7.ok) {
|
|
864
|
+
context.params.authenticated = true;
|
|
865
|
+
context.params.canU = true;
|
|
866
|
+
return context;
|
|
867
|
+
} else {
|
|
868
|
+
if (options != null && options.log) console.error('Ucan capabilities requirements not met: ', v, context.type, context.path);
|
|
869
|
+
if (!(options != null && options.noThrow)) throw new Error('Missing proper capabilities for this action: ' + context.type + ': ' + context.path + ' - ' + context.method);else {
|
|
870
|
+
context.params._no_throw_error = {
|
|
871
|
+
type: context.type,
|
|
872
|
+
method: context.method,
|
|
873
|
+
path: context.path
|
|
874
|
+
};
|
|
875
|
+
return context;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
};
|
|
882
|
+
const ucanAuth = (requiredCapabilities, options) => {
|
|
883
|
+
return async context => {
|
|
884
|
+
const configuration = context.app.get('authentication');
|
|
885
|
+
const core_path = configuration.core_path || 'core';
|
|
886
|
+
const entity = configuration.entity || 'login';
|
|
887
|
+
const existingLogin = symbolUcan._get(context.params, [core_path, entity]) || symbolUcan._get(context.params, 'login') || symbolUcan._get(context.params.connection, entity);
|
|
888
|
+
if (existingLogin) context.params[entity] = existingLogin;
|
|
889
|
+
const loginId = typeof existingLogin === 'string' ? existingLogin : existingLogin == null ? void 0 : existingLogin._id;
|
|
890
|
+
const hasLogin = !!(existingLogin && (typeof existingLogin === 'string' || !!loginId));
|
|
891
|
+
const existingUcan = symbolUcan._get(context.params, configuration.client_ucan || 'client_ucan');
|
|
892
|
+
if (options != null && options.log) console.log('ucan auth', 'hasLogin', hasLogin, 'loginId', loginId, 'existingUcan', !!existingUcan, 'core_path', core_path, 'entity', entity, 'core', context.params[core_path], 'params login', context.params.login, 'required capabilities', requiredCapabilities);
|
|
893
|
+
//Below for passing through auth with no required capabilities
|
|
894
|
+
if (requiredCapabilities === noThrow || requiredCapabilities && requiredCapabilities[context.method] === noThrow) return hasLogin ? context : await noThrowAuth(context);
|
|
895
|
+
const adminPass = ((options == null ? void 0 : options.adminPass) || []).includes(context.method) && (symbolUcan._get(context.params, 'admin_pass') || symbolUcan._get(context.params, [configuration.core_path, 'admin_pass']));
|
|
896
|
+
// If no login is present and no client UCAN is provided, perform authentication. Otherwise, reuse existing state/ucan.
|
|
897
|
+
if (!hasLogin && !existingUcan) context = adminPass || options != null && options.specialChange ? await noThrowAuth(context) : await bareAuth(context);
|
|
898
|
+
if (requiredCapabilities === anyAuth && !(options != null && options.specialChange)) {
|
|
899
|
+
context.params.authenticated = !!context.params[entity];
|
|
900
|
+
return context;
|
|
901
|
+
}
|
|
902
|
+
if (adminPass) return context;
|
|
903
|
+
if (!requiredCapabilities) return context;
|
|
904
|
+
return await checkUcan(requiredCapabilities, options)(context);
|
|
905
|
+
};
|
|
906
|
+
};
|
|
907
|
+
const allUcanAuth = (methods, options) => {
|
|
908
|
+
return async context => {
|
|
909
|
+
const config = context.app.get('authentication');
|
|
910
|
+
// if a login is already present in params[core_path][entity], don't overwrite it
|
|
911
|
+
const corePath = config.core_path || 'core';
|
|
912
|
+
const entityKey = config.entity || 'login';
|
|
913
|
+
const existingLogin = symbolUcan._get(context.params, [corePath, entityKey]);
|
|
914
|
+
if (!existingLogin) {
|
|
915
|
+
const entity = symbolUcan._get(context, ['auth', entityKey]);
|
|
916
|
+
if (entity) context = symbolUcan._set(context, [corePath, entityKey], entity);
|
|
917
|
+
}
|
|
918
|
+
if (context.type === 'before') {
|
|
919
|
+
const {
|
|
920
|
+
method
|
|
921
|
+
} = context;
|
|
922
|
+
if (methods[method] || methods['all']) {
|
|
923
|
+
return await ucanAuth(methods[method] || methods['all'], options)(context);
|
|
924
|
+
} else return context;
|
|
925
|
+
} else return context;
|
|
926
|
+
};
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
const updateUcan = () => {
|
|
930
|
+
return async context => {
|
|
931
|
+
const {
|
|
932
|
+
add = [],
|
|
933
|
+
remove = []
|
|
934
|
+
} = context.data;
|
|
935
|
+
//ensure capabilities were passed
|
|
936
|
+
if (!(add != null && add.length) && !(remove != null && remove.length)) throw new Error('No new capabilities passed');
|
|
937
|
+
//check ability to edit the affected capabilities
|
|
938
|
+
const {
|
|
939
|
+
secret,
|
|
940
|
+
ucan_aud,
|
|
941
|
+
entity,
|
|
942
|
+
ucan
|
|
943
|
+
} = context.app.get('authentication');
|
|
944
|
+
const rootIssuer = symbolUcan.encodeKeyPair({
|
|
945
|
+
secretKey: secret
|
|
946
|
+
}).did();
|
|
947
|
+
const checkAbilities = symbolUcan.stackAbilities([...add, ...remove]);
|
|
948
|
+
const canEdit = await symbolUcan.verifyUcan(symbolUcan._get(context.params, [entity, ucan]), {
|
|
949
|
+
audience: symbolUcan._get(context.params, ucan_aud),
|
|
950
|
+
requiredCapabilities: checkAbilities.map(a => {
|
|
951
|
+
return {
|
|
952
|
+
//TODO: possibly READ shouldn't have the ability to allow others to READ
|
|
953
|
+
capability: a,
|
|
954
|
+
rootIssuer
|
|
955
|
+
};
|
|
956
|
+
})
|
|
957
|
+
});
|
|
958
|
+
if (!(canEdit != null && canEdit.ok)) throw new Error('You don\'t have sufficient capabilities to grant those capabilities');
|
|
959
|
+
//prep edited ucan
|
|
960
|
+
const subjectId = context.id;
|
|
961
|
+
const service = context.data.service || 'logins';
|
|
962
|
+
const path = context.data.path || 'ucan';
|
|
963
|
+
const subject = await new CoreCall(service, context, {
|
|
964
|
+
skipJoins: true
|
|
965
|
+
}).get(subjectId);
|
|
966
|
+
const decoded = symbolUcan.parseUcan(symbolUcan._get(subject, path));
|
|
967
|
+
const {
|
|
968
|
+
aud,
|
|
969
|
+
att,
|
|
970
|
+
fct,
|
|
971
|
+
nbf,
|
|
972
|
+
prf
|
|
973
|
+
} = decoded.payload;
|
|
974
|
+
let capabilities = [...att];
|
|
975
|
+
if (remove != null && remove.length) capabilities = symbolUcan.reduceAbilities(remove, att);
|
|
976
|
+
if (add != null && add.length) capabilities = symbolUcan.stackAbilities([...att, ...add]);
|
|
977
|
+
const raw = await symbolUcan.buildUcan({
|
|
978
|
+
issuer: symbolUcan.encodeKeyPair({
|
|
979
|
+
secretKey: secret
|
|
980
|
+
}),
|
|
981
|
+
audience: aud,
|
|
982
|
+
lifetimeInSeconds: 60 * 60 * 24 * 60,
|
|
983
|
+
proofs: prf,
|
|
984
|
+
...context.data,
|
|
985
|
+
capabilities
|
|
986
|
+
});
|
|
987
|
+
const encoded = symbolUcan.ucanToken(raw);
|
|
988
|
+
const isValid = await symbolUcan.validateUcan(encoded);
|
|
989
|
+
if (!isValid) throw new Error('Invalid ucan generated when updating');
|
|
990
|
+
const patched = await new CoreCall(service, context).patch(subjectId, {
|
|
991
|
+
[path]: encoded
|
|
992
|
+
});
|
|
993
|
+
context.result = {
|
|
994
|
+
raw: context.data,
|
|
995
|
+
encoded,
|
|
996
|
+
subject: patched
|
|
997
|
+
};
|
|
998
|
+
return context;
|
|
999
|
+
};
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
exports.AuthService = AuthService;
|
|
1003
|
+
exports.CoreCall = CoreCall;
|
|
1004
|
+
exports.NotAuthError = NotAuthError;
|
|
1005
|
+
exports.UcanStrategy = UcanStrategy;
|
|
1006
|
+
exports.allUcanAuth = allUcanAuth;
|
|
1007
|
+
exports.anyAuth = anyAuth;
|
|
1008
|
+
exports.bareAuth = bareAuth;
|
|
1009
|
+
exports.checkUcan = checkUcan;
|
|
1010
|
+
exports.existsPath = existsPath;
|
|
1011
|
+
exports.getExists = getExists;
|
|
1012
|
+
exports.loadExists = loadExists;
|
|
1013
|
+
exports.modelCapabilities = modelCapabilities;
|
|
1014
|
+
exports.noThrow = noThrow;
|
|
1015
|
+
exports.noThrowAuth = noThrowAuth;
|
|
1016
|
+
exports.orVerifyLoop = orVerifyLoop;
|
|
1017
|
+
exports.setExists = setExists;
|
|
1018
|
+
exports.ucanAuth = ucanAuth;
|
|
1019
|
+
exports.updateUcan = updateUcan;
|
|
1020
|
+
exports.verifyAgainstReqs = verifyAgainstReqs;
|
|
2
1021
|
//# sourceMappingURL=index.cjs.map
|