@typekcz-nocobase-plugins/plugin-oidc-plus 1.0.2 → 1.0.4

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.
Files changed (75) hide show
  1. package/dist/client/index.js +1 -3
  2. package/dist/externalVersion.js +9 -9
  3. package/package.json +10 -10
  4. package/src/client/OIDCButton.tsx +70 -0
  5. package/src/client/Options.tsx +359 -0
  6. package/src/client/index.tsx +19 -0
  7. package/src/client/locale/index.ts +18 -0
  8. package/src/constants.ts +7 -0
  9. package/src/index.ts +2 -0
  10. package/src/locale/en-US.json +40 -0
  11. package/src/locale/es-ES.json +25 -0
  12. package/src/locale/fr-FR.json +21 -0
  13. package/src/locale/ko_KR.json +28 -0
  14. package/src/locale/pt-BR.json +21 -0
  15. package/src/locale/zh-CN.json +28 -0
  16. package/src/server/__tests__/oidc.test.ts +283 -0
  17. package/src/server/actions/getAuthUrl.ts +25 -0
  18. package/src/server/actions/redirect.ts +32 -0
  19. package/src/server/index.ts +1 -0
  20. package/src/server/oidc-auth.ts +169 -0
  21. package/src/server/plugin.ts +63 -0
  22. package/src/swagger/index.ts +157 -0
  23. package/dist/node_modules/nanoid/LICENSE +0 -20
  24. package/dist/node_modules/nanoid/async/index.browser.cjs +0 -34
  25. package/dist/node_modules/nanoid/async/index.browser.js +0 -34
  26. package/dist/node_modules/nanoid/async/index.cjs +0 -35
  27. package/dist/node_modules/nanoid/async/index.d.ts +0 -56
  28. package/dist/node_modules/nanoid/async/index.js +0 -35
  29. package/dist/node_modules/nanoid/async/index.native.js +0 -26
  30. package/dist/node_modules/nanoid/async/package.json +0 -12
  31. package/dist/node_modules/nanoid/bin/nanoid.cjs +0 -55
  32. package/dist/node_modules/nanoid/index.browser.cjs +0 -34
  33. package/dist/node_modules/nanoid/index.browser.js +0 -34
  34. package/dist/node_modules/nanoid/index.cjs +0 -1
  35. package/dist/node_modules/nanoid/index.d.ts +0 -91
  36. package/dist/node_modules/nanoid/index.js +0 -45
  37. package/dist/node_modules/nanoid/nanoid.js +0 -1
  38. package/dist/node_modules/nanoid/non-secure/index.cjs +0 -21
  39. package/dist/node_modules/nanoid/non-secure/index.d.ts +0 -33
  40. package/dist/node_modules/nanoid/non-secure/index.js +0 -21
  41. package/dist/node_modules/nanoid/non-secure/package.json +0 -6
  42. package/dist/node_modules/nanoid/package.json +0 -1
  43. package/dist/node_modules/nanoid/url-alphabet/index.cjs +0 -3
  44. package/dist/node_modules/nanoid/url-alphabet/index.js +0 -3
  45. package/dist/node_modules/nanoid/url-alphabet/package.json +0 -6
  46. package/dist/node_modules/openid-client/lib/client.js +0 -1849
  47. package/dist/node_modules/openid-client/lib/device_flow_handle.js +0 -125
  48. package/dist/node_modules/openid-client/lib/errors.js +0 -55
  49. package/dist/node_modules/openid-client/lib/helpers/assert.js +0 -24
  50. package/dist/node_modules/openid-client/lib/helpers/base64url.js +0 -13
  51. package/dist/node_modules/openid-client/lib/helpers/client.js +0 -211
  52. package/dist/node_modules/openid-client/lib/helpers/consts.js +0 -7
  53. package/dist/node_modules/openid-client/lib/helpers/decode_jwt.js +0 -27
  54. package/dist/node_modules/openid-client/lib/helpers/deep_clone.js +0 -1
  55. package/dist/node_modules/openid-client/lib/helpers/defaults.js +0 -27
  56. package/dist/node_modules/openid-client/lib/helpers/generators.js +0 -14
  57. package/dist/node_modules/openid-client/lib/helpers/is_key_object.js +0 -4
  58. package/dist/node_modules/openid-client/lib/helpers/is_plain_object.js +0 -1
  59. package/dist/node_modules/openid-client/lib/helpers/issuer.js +0 -111
  60. package/dist/node_modules/openid-client/lib/helpers/keystore.js +0 -298
  61. package/dist/node_modules/openid-client/lib/helpers/merge.js +0 -24
  62. package/dist/node_modules/openid-client/lib/helpers/pick.js +0 -9
  63. package/dist/node_modules/openid-client/lib/helpers/process_response.js +0 -71
  64. package/dist/node_modules/openid-client/lib/helpers/request.js +0 -200
  65. package/dist/node_modules/openid-client/lib/helpers/unix_timestamp.js +0 -1
  66. package/dist/node_modules/openid-client/lib/helpers/weak_cache.js +0 -1
  67. package/dist/node_modules/openid-client/lib/helpers/webfinger_normalize.js +0 -71
  68. package/dist/node_modules/openid-client/lib/helpers/www_authenticate_parser.js +0 -14
  69. package/dist/node_modules/openid-client/lib/index.js +0 -1
  70. package/dist/node_modules/openid-client/lib/issuer.js +0 -191
  71. package/dist/node_modules/openid-client/lib/issuer_registry.js +0 -3
  72. package/dist/node_modules/openid-client/lib/passport_strategy.js +0 -205
  73. package/dist/node_modules/openid-client/lib/token_set.js +0 -35
  74. package/dist/node_modules/openid-client/package.json +0 -1
  75. package/dist/node_modules/openid-client/types/index.d.ts +0 -622
@@ -7,6 +7,4 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- (function(o,n){typeof exports=="object"&&typeof module!="undefined"?n(exports,require("@nocobase/client"),require("@nocobase/plugin-auth/client"),require("react/jsx-runtime"),require("@ant-design/icons"),require("antd"),require("react"),require("react-i18next"),require("react-router-dom"),require("@formily/antd-v5"),require("@formily/react")):typeof define=="function"&&define.amd?define(["exports","@nocobase/client","@nocobase/plugin-auth/client","react/jsx-runtime","@ant-design/icons","antd","react","react-i18next","react-router-dom","@formily/antd-v5","@formily/react"],n):(o=typeof globalThis!="undefined"?globalThis:o||self,n(o["@typekcz-nocobase-plugins/plugin-oidc-plus"]={},o["@nocobase/client"],o["@nocobase/plugin-auth"],o.jsxRuntime,o["@ant-design/icons"],o.antd,o.react,o["react-i18next"],o["react-router-dom"],o["@formily/antd-v5"],o["@formily/react"]))})(this,function(o,n,h,s,v,u,b,I,d,y,U){"use strict";var w=(o,n,h)=>new Promise((s,v)=>{var u=d=>{try{I(h.next(d))}catch(y){v(y)}},b=d=>{try{I(h.throw(d))}catch(y){v(y)}},I=d=>d.done?s(d.value):Promise.resolve(d.value).then(u,b);I((h=h.apply(o,n)).next())});const j="OIDC+",T="tnp_oidc_plus_logout",P="oidc";function c(e){return n.i18n.t(e,{ns:P})}function C(){return I.useTranslation(P)}/*! js-cookie v3.0.5 | MIT */function S(e){for(var a=1;a<arguments.length;a++){var l=arguments[a];for(var m in l)e[m]=l[m]}return e}var q={read:function(e){return e[0]==='"'&&(e=e.slice(1,-1)),e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(e){return encodeURIComponent(e).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}};function F(e,a){function l(t,x,r){if(typeof document!="undefined"){r=S({},a,r),typeof r.expires=="number"&&(r.expires=new Date(Date.now()+r.expires*864e5)),r.expires&&(r.expires=r.expires.toUTCString()),t=encodeURIComponent(t).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var i="";for(var p in r)r[p]&&(i+="; "+p,r[p]!==!0&&(i+="="+r[p].split(";")[0]));return document.cookie=t+"="+e.write(x,t)+i}}function m(t){if(!(typeof document=="undefined"||arguments.length&&!t)){for(var x=document.cookie?document.cookie.split("; "):[],r={},i=0;i<x.length;i++){var p=x[i].split("="),f=p.slice(1).join("=");try{var g=decodeURIComponent(p[0]);if(r[g]=e.read(f,g),t===g)break}catch(D){}}return t?r[t]:r}}return Object.create({set:l,get:m,remove:function(t,x){l(t,"",S({},x,{expires:-1}))},withAttributes:function(t){return F(this.converter,S({},this.attributes,t))},withConverter:function(t){return F(S({},this.converter,t),this.attributes)}},{attributes:{value:Object.freeze(a)},converter:{value:Object.freeze(e)}})}var k=F(q,{path:"/"});const E=({authenticator:e})=>{const{t:a}=C(),l=n.useAPIClient(),m=d.useLocation(),t=new URLSearchParams(m.search),x=t.get("redirect"),r=()=>w(this,null,function*(){var f;const i=yield l.request({method:"post",url:"oidc:getAuthUrl",headers:{"X-Authenticator":e.name},data:{redirect:x}}),p=(f=i==null?void 0:i.data)==null?void 0:f.data;window.location.replace(p)});return b.useEffect(()=>{const i=k.get(T);if(i){const g=new URL(i);g.searchParams.set("post_logout_redirect_uri",window.location.href),console.log(T,{domain:window.location.hostname}),k.remove(T,{domain:window.location.hostname}),window.location.href=g.href}const p=t.get("authenticator"),f=t.get("error");if(p===e.name&&f){u.message.error(a(f));return}}),s.jsx(u.Space,{direction:"vertical",className:n.css`
11
- display: flex;
12
- `,children:s.jsx(u.Button,{shape:"round",block:!0,icon:s.jsx(v.LoginOutlined,{}),onClick:r,children:a(e.title)})})},O={type:"object",properties:{public:{type:"object",properties:{autoSignup:{"x-decorator":"FormItem",type:"boolean",title:'{{t("Sign up automatically when the user does not exist")}}',"x-component":"Checkbox",default:!0}}},oidc:{type:"object",properties:{collapse:{type:"void","x-component":"FormTab",properties:{basic:{type:"void","x-component":"FormTab.TabPane","x-component-props":{tab:c("Basic configuration")},properties:{issuer:{type:"string",title:'{{t("Issuer")}}',"x-component":"Input","x-decorator":"FormItem",required:!0},clientId:{type:"string",title:'{{t("Client ID")}}',"x-component":"Input","x-decorator":"FormItem",required:!0},clientSecret:{type:"string",title:'{{t("Client Secret")}}',"x-component":"Input","x-decorator":"FormItem",required:!0},scope:{type:"string",title:'{{t("scope")}}',"x-component":"Input","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("Default: openid profile email")}}'}},idTokenSignedResponseAlg:{type:"string",title:'{{t("id_token signed response algorithm")}}',"x-component":"Select","x-decorator":"FormItem",enum:[{label:"HS256",value:"HS256"},{label:"HS384",value:"HS384"},{label:"HS512",value:"HS512"},{label:"RS256",value:"RS256"},{label:"RS384",value:"RS384"},{label:"RS512",value:"RS512"},{label:"ES256",value:"ES256"},{label:"ES384",value:"ES384"},{label:"ES512",value:"ES512"},{label:"PS256",value:"PS256"},{label:"PS384",value:"PS384"},{label:"PS512",value:"PS512"}]}}},mapping:{type:"void","x-component":"FormTab.TabPane","x-component-props":{tab:c("Field mapping")},properties:{fieldMap:{title:'{{t("Field Map")}}',type:"array","x-decorator":"FormItem","x-component":"ArrayItems",items:{type:"object","x-decorator":"ArrayItems.Item",properties:{space:{type:"void","x-component":"Space",properties:{source:{type:"string","x-decorator":"FormItem","x-component":"Input","x-component-props":{placeholder:'{{t("source")}}'}},target:{type:"string","x-decorator":"FormItem","x-component":"Input","x-component-props":{placeholder:'{{t("target")}}'}},remove:{type:"void","x-decorator":"FormItem","x-component":"ArrayItems.Remove"}}}}},properties:{add:{type:"void",title:"Add","x-component":"ArrayItems.Addition"}}},userBindField:{type:"string",title:'{{t("Use this field to bind the user")}}',"x-component":"Select","x-decorator":"FormItem",default:"email",enum:[{label:c("Email"),value:"email"},{label:c("Username"),value:"username"}],required:!0}}},advanced:{type:"void","x-component":"FormTab.TabPane","x-component-props":{tab:c("Advanced configuration")},properties:{logout:{type:"boolean",title:'{{t("RP-initiated logout")}}',"x-component":"Checkbox","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("Performs logout on the issuer (uses end_session_endpoint in the issuer configuration)")}}'}},http:{type:"boolean",title:'{{t("HTTP")}}',"x-component":"Checkbox","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("Check if NocoBase is running on HTTP protocol")}}'}},port:{type:"number",title:'{{t("Port")}}',"x-component":"InputNumber","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("The port number of the NocoBase service if it is not 80 or 443")}}'},"x-component-props":{style:{width:"15%",minWidth:"100px"}}},stateToken:{type:"string",title:'{{t("State token")}}',"x-component":"Input","x-decorator":"FormItem",description:c("The state token helps prevent CSRF attacks. It's recommended to leave it blank for automatic random generation.")},exchangeBodyKeys:{type:"array",title:'{{t("Pass parameters in the authorization code grant exchange")}}',"x-decorator":"FormItem","x-component":"ArrayItems",default:[{paramName:"",optionsKey:"clientId"},{paramName:"",optionsKey:"clientSecret"}],items:{type:"object","x-decorator":"ArrayItems.Item",properties:{space:{type:"void","x-component":"Space",properties:{enabled:{type:"boolean","x-decorator":"FormItem","x-component":"Checkbox"},optionsKey:{type:"string","x-decorator":"FormItem","x-decorator-props":{style:{width:"100px"}},"x-component":"Select","x-read-pretty":!0,enum:[{label:c("Client ID"),value:"clientId"},{label:c("Client Secret"),value:"clientSecret"}]},paramName:{type:"string","x-decorator":"FormItem","x-component":"Input","x-component-props":{placeholder:'{{t("Parameter name")}}'}}}}}}},userInfoMethod:{type:"string",title:'{{t("Method to call the user info endpoint")}}',"x- decorator":"FormItem","x-component":"Radio.Group",default:"GET",enum:[{label:"GET",value:"GET"},{label:"POST",value:"POST"}],"x-reactions":[{dependencies:[".accessTokenVia"],when:'{{$deps[0] === "query"}}',fulfill:{state:{value:"GET"}}},{dependencies:[".accessTokenVia"],when:'{{$deps[0] === "body"}}',fulfill:{state:{value:"POST"}}}]},accessTokenVia:{type:"string",title:'{{t("Where to put the access token when calling the user info endpoint")}}',"x- decorator":"FormItem","x-component":"Radio.Group",default:"header",enum:[{label:c("Header"),value:"header"},{label:c("Body (Use with POST method)"),value:"body"},{label:c("Query parameters (Use with GET method)"),value:"query"}]}}}}}}},usage:{type:"void","x-component":"Usage"}}},R=U.observer(()=>{const{t:e}=C(),a=n.useApp(),l=b.useMemo(()=>a.getApiUrl("oidc:redirect"),[a]),m=t=>{navigator.clipboard.writeText(t),u.message.success(e("Copied"))};return s.jsx(u.Card,{title:e("Usage"),type:"inner",children:s.jsx(n.FormItem,{label:e("Redirect URL"),children:s.jsx(n.Input,{value:l,disabled:!0,addonBefore:s.jsx(v.CopyOutlined,{onClick:()=>m(l)})})})})},{displayName:"Usage"}),B=()=>{const{t:e}=C();return s.jsx(n.SchemaComponent,{scope:{t:e},components:{Usage:R,ArrayItems:y.ArrayItems,Space:u.Space,FormTab:y.FormTab},schema:O})};class A extends n.Plugin{load(){return w(this,null,function*(){this.app.pm.get(h).registerType(j,{components:{SignInButton:E,AdminSettingsForm:B}})})}}o.PluginOIDCClient=A,o.default=A,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
10
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react-i18next"),require("@nocobase/plugin-auth/client"),require("@nocobase/client"),require("react-router-dom"),require("react"),require("@formily/antd-v5"),require("@formily/react"),require("@ant-design/icons"),require("antd")):"function"==typeof define&&define.amd?define("@typekcz-nocobase-plugins/plugin-oidc-plus",["react-i18next","@nocobase/plugin-auth/client","@nocobase/client","react-router-dom","react","@formily/antd-v5","@formily/react","@ant-design/icons","antd"],t):"object"==typeof exports?exports["@typekcz-nocobase-plugins/plugin-oidc-plus"]=t(require("react-i18next"),require("@nocobase/plugin-auth/client"),require("@nocobase/client"),require("react-router-dom"),require("react"),require("@formily/antd-v5"),require("@formily/react"),require("@ant-design/icons"),require("antd")):e["@typekcz-nocobase-plugins/plugin-oidc-plus"]=t(e["react-i18next"],e["@nocobase/plugin-auth/client"],e["@nocobase/client"],e["react-router-dom"],e.react,e["@formily/antd-v5"],e["@formily/react"],e["@ant-design/icons"],e.antd)}(self,function(e,t,r,o,n,i,a,c,u){return function(){"use strict";var l={482:function(e){e.exports=c},632:function(e){e.exports=i},505:function(e){e.exports=a},772:function(e){e.exports=r},689:function(e){e.exports=t},721:function(e){e.exports=u},156:function(e){e.exports=n},238:function(t){t.exports=e},128:function(e){e.exports=o}},p={};function s(e){var t=p[e];if(void 0!==t)return t.exports;var r=p[e]={exports:{}};return l[e](r,r.exports,s),r.exports}s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,{a:t}),t},s.d=function(e,t){for(var r in t)s.o(t,r)&&!s.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},s.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var d={};return!function(){s.r(d),s.d(d,{default:function(){return R},PluginOIDCClient:function(){return j}});var e=s(772),t=s(689),r=s.n(t),o="tnp_oidc_plus_logout",n=s(482),i=s(721),a=s(156),c=s.n(a),u=s(238),l="oidc";function p(t){return e.i18n.t(t,{ns:l})}function f(){return(0,u.useTranslation)(l)}var m=s(128);function y(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var o in r)e[o]=r[o]}return e}var b=function e(t,r){function o(e,o,n){if("undefined"!=typeof document){"number"==typeof(n=y({},r,n)).expires&&(n.expires=new Date(Date.now()+864e5*n.expires)),n.expires&&(n.expires=n.expires.toUTCString()),e=encodeURIComponent(e).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var i="";for(var a in n)n[a]&&(i+="; "+a,!0!==n[a]&&(i+="="+n[a].split(";")[0]));return document.cookie=e+"="+t.write(o,e)+i}}return Object.create({set:o,get:function(e){if("undefined"!=typeof document&&(!arguments.length||e)){for(var r=document.cookie?document.cookie.split("; "):[],o={},n=0;n<r.length;n++){var i=r[n].split("="),a=i.slice(1).join("=");try{var c=decodeURIComponent(i[0]);if(o[c]=t.read(a,c),e===c)break}catch(e){}}return e?o[e]:o}},remove:function(e,t){o(e,"",y({},t,{expires:-1}))},withAttributes:function(t){return e(this.converter,y({},this.attributes,t))},withConverter:function(t){return e(y({},this.converter,t),this.attributes)}},{attributes:{value:Object.freeze(r)},converter:{value:Object.freeze(t)}})}({read:function(e){return'"'===e[0]&&(e=e.slice(1,-1)),e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(e){return encodeURIComponent(e).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}},{path:"/"});function v(e,t,r,o,n,i,a){try{var c=e[i](a),u=c.value}catch(e){r(e);return}c.done?t(u):Promise.resolve(u).then(o,n)}function h(){var e,t,r=(e=["\n display: flex;\n "],t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}})));return h=function(){return r},r}var x=function(t){var r,u,l=t.authenticator,p=f().t,s=(0,e.useAPIClient)(),d=new URLSearchParams((0,m.useLocation)().search),y=d.get("redirect"),x=(r=function(){var e,t,r;return function(e,t){var r,o,n,i,a={label:0,sent:function(){if(1&n[0])throw n[1];return n[1]},trys:[],ops:[]};return i={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function c(i){return function(c){var u=[i,c];if(r)throw TypeError("Generator is already executing.");for(;a;)try{if(r=1,o&&(n=2&u[0]?o.return:u[0]?o.throw||((n=o.return)&&n.call(o),0):o.next)&&!(n=n.call(o,u[1])).done)return n;switch(o=0,n&&(u=[2&u[0],n.value]),u[0]){case 0:case 1:n=u;break;case 4:return a.label++,{value:u[1],done:!1};case 5:a.label++,o=u[1],u=[0];continue;case 7:u=a.ops.pop(),a.trys.pop();continue;default:if(!(n=(n=a.trys).length>0&&n[n.length-1])&&(6===u[0]||2===u[0])){a=0;continue}if(3===u[0]&&(!n||u[1]>n[0]&&u[1]<n[3])){a.label=u[1];break}if(6===u[0]&&a.label<n[1]){a.label=n[1],n=u;break}if(n&&a.label<n[2]){a.label=n[2],a.ops.push(u);break}n[2]&&a.ops.pop(),a.trys.pop();continue}u=t.call(e,a)}catch(e){u=[6,e],o=0}finally{r=n=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}}}(this,function(o){switch(o.label){case 0:return[4,s.request({method:"post",url:"oidc:getAuthUrl",headers:{"X-Authenticator":l.name},data:{redirect:y}})];case 1:return r=null==(t=o.sent())||null==(e=t.data)?void 0:e.data,window.location.replace(r),[2]}})},u=function(){var e=this,t=arguments;return new Promise(function(o,n){var i=r.apply(e,t);function a(e){v(i,o,n,a,c,"next",e)}function c(e){v(i,o,n,a,c,"throw",e)}a(void 0)})},function(){return u.apply(this,arguments)});return(0,a.useEffect)(function(){var e=b.get(o);if(e){var t=new URL(e);t.searchParams.set("post_logout_redirect_uri",window.location.href),b.remove(o,{domain:window.location.hostname}),window.location.href=t.href}var r=d.get("authenticator"),n=d.get("error");if(r===l.name&&n)return void i.message.error(p(n))}),c().createElement(i.Space,{direction:"vertical",className:(0,e.css)(h())},c().createElement(i.Button,{shape:"round",block:!0,icon:c().createElement(n.LoginOutlined,null),onClick:x},p(l.title)))},g=s(632),S=s(505),I={type:"object",properties:{public:{type:"object",properties:{autoSignup:{"x-decorator":"FormItem",type:"boolean",title:'{{t("Sign up automatically when the user does not exist")}}',"x-component":"Checkbox",default:!0}}},oidc:{type:"object",properties:{collapse:{type:"void","x-component":"FormTab",properties:{basic:{type:"void","x-component":"FormTab.TabPane","x-component-props":{tab:p("Basic configuration")},properties:{issuer:{type:"string",title:'{{t("Issuer")}}',"x-component":"Input","x-decorator":"FormItem",required:!0},clientId:{type:"string",title:'{{t("Client ID")}}',"x-component":"Input","x-decorator":"FormItem",required:!0},clientSecret:{type:"string",title:'{{t("Client Secret")}}',"x-component":"Input","x-decorator":"FormItem",required:!0},scope:{type:"string",title:'{{t("scope")}}',"x-component":"Input","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("Default: openid profile email")}}'}},idTokenSignedResponseAlg:{type:"string",title:'{{t("id_token signed response algorithm")}}',"x-component":"Select","x-decorator":"FormItem",enum:[{label:"HS256",value:"HS256"},{label:"HS384",value:"HS384"},{label:"HS512",value:"HS512"},{label:"RS256",value:"RS256"},{label:"RS384",value:"RS384"},{label:"RS512",value:"RS512"},{label:"ES256",value:"ES256"},{label:"ES384",value:"ES384"},{label:"ES512",value:"ES512"},{label:"PS256",value:"PS256"},{label:"PS384",value:"PS384"},{label:"PS512",value:"PS512"}]}}},mapping:{type:"void","x-component":"FormTab.TabPane","x-component-props":{tab:p("Field mapping")},properties:{fieldMap:{title:'{{t("Field Map")}}',type:"array","x-decorator":"FormItem","x-component":"ArrayItems",items:{type:"object","x-decorator":"ArrayItems.Item",properties:{space:{type:"void","x-component":"Space",properties:{source:{type:"string","x-decorator":"FormItem","x-component":"Input","x-component-props":{placeholder:'{{t("source")}}'}},target:{type:"string","x-decorator":"FormItem","x-component":"Input","x-component-props":{placeholder:'{{t("target")}}'}},remove:{type:"void","x-decorator":"FormItem","x-component":"ArrayItems.Remove"}}}}},properties:{add:{type:"void",title:"Add","x-component":"ArrayItems.Addition"}}},userBindField:{type:"string",title:'{{t("Use this field to bind the user")}}',"x-component":"Select","x-decorator":"FormItem",default:"email",enum:[{label:p("Email"),value:"email"},{label:p("Username"),value:"username"}],required:!0}}},advanced:{type:"void","x-component":"FormTab.TabPane","x-component-props":{tab:p("Advanced configuration")},properties:{logout:{type:"boolean",title:'{{t("RP-initiated logout")}}',"x-component":"Checkbox","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("Performs logout on the issuer (uses end_session_endpoint in the issuer configuration)")}}'}},http:{type:"boolean",title:'{{t("HTTP")}}',"x-component":"Checkbox","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("Check if NocoBase is running on HTTP protocol")}}'}},port:{type:"number",title:'{{t("Port")}}',"x-component":"InputNumber","x-decorator":"FormItem","x-decorator-props":{tooltip:'{{t("The port number of the NocoBase service if it is not 80 or 443")}}'},"x-component-props":{style:{width:"15%",minWidth:"100px"}}},stateToken:{type:"string",title:'{{t("State token")}}',"x-component":"Input","x-decorator":"FormItem",description:p("The state token helps prevent CSRF attacks. It's recommended to leave it blank for automatic random generation.")},exchangeBodyKeys:{type:"array",title:'{{t("Pass parameters in the authorization code grant exchange")}}',"x-decorator":"FormItem","x-component":"ArrayItems",default:[{paramName:"",optionsKey:"clientId"},{paramName:"",optionsKey:"clientSecret"}],items:{type:"object","x-decorator":"ArrayItems.Item",properties:{space:{type:"void","x-component":"Space",properties:{enabled:{type:"boolean","x-decorator":"FormItem","x-component":"Checkbox"},optionsKey:{type:"string","x-decorator":"FormItem","x-decorator-props":{style:{width:"100px"}},"x-component":"Select","x-read-pretty":!0,enum:[{label:p("Client ID"),value:"clientId"},{label:p("Client Secret"),value:"clientSecret"}]},paramName:{type:"string","x-decorator":"FormItem","x-component":"Input","x-component-props":{placeholder:'{{t("Parameter name")}}'}}}}}}},userInfoMethod:{type:"string",title:'{{t("Method to call the user info endpoint")}}',"x- decorator":"FormItem","x-component":"Radio.Group",default:"GET",enum:[{label:"GET",value:"GET"},{label:"POST",value:"POST"}],"x-reactions":[{dependencies:[".accessTokenVia"],when:'{{$deps[0] === "query"}}',fulfill:{state:{value:"GET"}}},{dependencies:[".accessTokenVia"],when:'{{$deps[0] === "body"}}',fulfill:{state:{value:"POST"}}}]},accessTokenVia:{type:"string",title:'{{t("Where to put the access token when calling the user info endpoint")}}',"x- decorator":"FormItem","x-component":"Radio.Group",default:"header",enum:[{label:p("Header"),value:"header"},{label:p("Body (Use with POST method)"),value:"body"},{label:p("Query parameters (Use with GET method)"),value:"query"}]}}}}}}},usage:{type:"void","x-component":"Usage"}}},w=(0,S.observer)(function(){var t=f().t,r=(0,e.useApp)(),o=(0,a.useMemo)(function(){return r.getApiUrl("oidc:redirect")},[r]),u=function(e){navigator.clipboard.writeText(e),i.message.success(t("Copied"))};return c().createElement(i.Card,{title:t("Usage"),type:"inner"},c().createElement(e.FormItem,{label:t("Redirect URL")},c().createElement(e.Input,{value:o,disabled:!0,addonBefore:c().createElement(n.CopyOutlined,{onClick:function(){return u(o)}})})))},{displayName:"Usage"}),T=function(){var t=f().t;return c().createElement(e.SchemaComponent,{scope:{t:t},components:{Usage:w,ArrayItems:g.ArrayItems,Space:i.Space,FormTab:g.FormTab},schema:I})};function P(e,t,r,o,n,i,a){try{var c=e[i](a),u=c.value}catch(e){r(e);return}c.done?t(u):Promise.resolve(u).then(o,n)}function F(e,t,r){return(F=E()?Reflect.construct:function(e,t,r){var o=[null];o.push.apply(o,t);var n=new(Function.bind.apply(e,o));return r&&C(n,r.prototype),n}).apply(null,arguments)}function k(e){return(k=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function C(e,t){return(C=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function O(e){var t="function"==typeof Map?new Map:void 0;return(O=function(e){if(null===e||-1===Function.toString.call(e).indexOf("[native code]"))return e;if("function"!=typeof e)throw 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,r)}function r(){return F(e,arguments,k(this).constructor)}return r.prototype=Object.create(e.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),C(r,e)})(e)}function E(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(E=function(){return!!e})()}var j=function(e){var t;if("function"!=typeof e&&null!==e)throw TypeError("Super expression must either be null or a function");function o(){var e,t;if(!(this instanceof o))throw TypeError("Cannot call a class as a function");return e=o,t=arguments,e=k(e),function(e,t){var r;if(t&&("object"==((r=t)&&"undefined"!=typeof Symbol&&r.constructor===Symbol?"symbol":typeof r)||"function"==typeof t))return t;if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(this,E()?Reflect.construct(e,t||[],k(this).constructor):e.apply(this,t))}return o.prototype=Object.create(e&&e.prototype,{constructor:{value:o,writable:!0,configurable:!0}}),e&&C(o,e),t=[{key:"load",value:function(){var e,t=this;return(e=function(){return function(e,t){var r,o,n,i,a={label:0,sent:function(){if(1&n[0])throw n[1];return n[1]},trys:[],ops:[]};return i={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function c(i){return function(c){var u=[i,c];if(r)throw TypeError("Generator is already executing.");for(;a;)try{if(r=1,o&&(n=2&u[0]?o.return:u[0]?o.throw||((n=o.return)&&n.call(o),0):o.next)&&!(n=n.call(o,u[1])).done)return n;switch(o=0,n&&(u=[2&u[0],n.value]),u[0]){case 0:case 1:n=u;break;case 4:return a.label++,{value:u[1],done:!1};case 5:a.label++,o=u[1],u=[0];continue;case 7:u=a.ops.pop(),a.trys.pop();continue;default:if(!(n=(n=a.trys).length>0&&n[n.length-1])&&(6===u[0]||2===u[0])){a=0;continue}if(3===u[0]&&(!n||u[1]>n[0]&&u[1]<n[3])){a.label=u[1];break}if(6===u[0]&&a.label<n[1]){a.label=n[1],n=u;break}if(n&&a.label<n[2]){a.label=n[2],a.ops.push(u);break}n[2]&&a.ops.pop(),a.trys.pop();continue}u=t.call(e,a)}catch(e){u=[6,e],o=0}finally{r=n=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}}}(this,function(e){return t.app.pm.get(r()).registerType("OIDC+",{components:{SignInButton:x,AdminSettingsForm:T}}),[2]})},function(){var t=this,r=arguments;return new Promise(function(o,n){var i=e.apply(t,r);function a(e){P(i,o,n,a,c,"next",e)}function c(e){P(i,o,n,a,c,"throw",e)}a(void 0)})})()}}],function(e,t){for(var r=0;r<t.length;r++){var o=t[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}(o.prototype,t),o}(O(e.Plugin)),R=j}(),d}()});
@@ -8,16 +8,16 @@
8
8
  */
9
9
 
10
10
  module.exports = {
11
- "@ant-design/icons": "5.2.6",
12
- "@nocobase/client": "1.3.19-beta",
13
- "antd": "5.12.8",
11
+ "@ant-design/icons": "5.6.1",
12
+ "@nocobase/client": "1.8.23",
13
+ "antd": "5.24.2",
14
14
  "react": "18.2.0",
15
- "react-router-dom": "6.21.0",
16
- "@nocobase/plugin-auth": "1.3.19-beta",
17
- "@formily/antd-v5": "1.1.9",
15
+ "react-router-dom": "6.28.1",
16
+ "@nocobase/plugin-auth": "1.8.23",
17
+ "@formily/antd-v5": "1.2.3",
18
18
  "@formily/react": "2.3.0",
19
- "@nocobase/auth": "1.3.19-beta",
20
- "@nocobase/server": "1.3.19-beta",
19
+ "@nocobase/auth": "1.8.23",
20
+ "@nocobase/server": "1.8.23",
21
21
  "react-i18next": "11.18.6",
22
- "@nocobase/actions": "1.3.19-beta"
22
+ "@nocobase/actions": "1.8.23"
23
23
  };
package/package.json CHANGED
@@ -2,29 +2,29 @@
2
2
  "name": "@typekcz-nocobase-plugins/plugin-oidc-plus",
3
3
  "displayName": "Auth: OIDC Plus",
4
4
  "description": "OIDC (OpenID Connect) authentication with extra features.",
5
- "version": "1.0.2",
5
+ "version": "1.0.4",
6
6
  "license": "AGPL-3.0",
7
7
  "main": "dist/server/index.js",
8
8
  "devDependencies": {
9
9
  "@ant-design/icons": "5.x",
10
10
  "@formily/antd-v5": "1.x",
11
11
  "@formily/react": "2.x",
12
- "ahooks": "3.7.2",
12
+ "ahooks": "^3.7.2",
13
13
  "antd": "5.x",
14
- "nanoid": "3.3.4",
14
+ "nanoid": "^3.3.4",
15
15
  "openid-client": "^5.4.2",
16
16
  "react": "18.x",
17
17
  "react-i18next": "^11.15.1",
18
18
  "js-cookie": "^3.0.5"
19
19
  },
20
20
  "peerDependencies": {
21
- "@nocobase/actions": "^1.3.19-beta",
22
- "@nocobase/auth": "^1.3.19-beta",
23
- "@nocobase/client": "^1.3.19-beta",
24
- "@nocobase/database": "^1.3.19-beta",
25
- "@nocobase/plugin-auth": "^1.3.19-beta",
26
- "@nocobase/server": "^1.3.19-beta",
27
- "@nocobase/test": "^1.3.19-beta"
21
+ "@nocobase/actions": "1.x",
22
+ "@nocobase/auth": "1.x",
23
+ "@nocobase/client": "1.x",
24
+ "@nocobase/database": "1.x",
25
+ "@nocobase/plugin-auth": "1.x",
26
+ "@nocobase/server": "1.x",
27
+ "@nocobase/test": "1.x"
28
28
  },
29
29
  "keywords": [
30
30
  "Authentication"
@@ -0,0 +1,70 @@
1
+ import { LoginOutlined } from '@ant-design/icons';
2
+ import { css, useAPIClient } from '@nocobase/client';
3
+ import { Button, Space, message } from 'antd';
4
+ import React, { useEffect } from 'react';
5
+ import { useOidcTranslation } from './locale';
6
+ import { useLocation } from 'react-router-dom';
7
+ import { Authenticator } from '@nocobase/plugin-auth/client';
8
+ import Cookies from 'js-cookie';
9
+ import { logoutCookieName } from '../constants';
10
+
11
+ export interface OIDCProvider {
12
+ clientId: string;
13
+ title: string;
14
+ }
15
+
16
+ export const OIDCButton = ({ authenticator }: { authenticator: Authenticator }) => {
17
+ const { t } = useOidcTranslation();
18
+ const api = useAPIClient();
19
+ const location = useLocation();
20
+ const params = new URLSearchParams(location.search);
21
+ const redirect = params.get('redirect');
22
+
23
+ const login = async () => {
24
+ const response = await api.request({
25
+ method: 'post',
26
+ url: 'oidc:getAuthUrl',
27
+ headers: {
28
+ 'X-Authenticator': authenticator.name,
29
+ },
30
+ data: {
31
+ redirect,
32
+ },
33
+ });
34
+
35
+ const authUrl = response?.data?.data;
36
+ window.location.replace(authUrl);
37
+ };
38
+
39
+ useEffect(() => {
40
+ const logoutUrl = Cookies.get(logoutCookieName);
41
+ if (logoutUrl) {
42
+ const logoutUrlObj = new URL(logoutUrl);
43
+ logoutUrlObj.searchParams.set('post_logout_redirect_uri', window.location.href);
44
+ Cookies.remove(logoutCookieName, { domain: window.location.hostname });
45
+ window.location.href = logoutUrlObj.href;
46
+ }
47
+ const name = params.get('authenticator');
48
+ const error = params.get('error');
49
+ if (name !== authenticator.name) {
50
+ return;
51
+ }
52
+ if (error) {
53
+ message.error(t(error));
54
+ return;
55
+ }
56
+ });
57
+
58
+ return (
59
+ <Space
60
+ direction="vertical"
61
+ className={css`
62
+ display: flex;
63
+ `}
64
+ >
65
+ <Button shape="round" block icon={<LoginOutlined />} onClick={login}>
66
+ {t(authenticator.title)}
67
+ </Button>
68
+ </Space>
69
+ );
70
+ };
@@ -0,0 +1,359 @@
1
+ import { CopyOutlined } from '@ant-design/icons';
2
+ import { ArrayItems, FormTab } from '@formily/antd-v5';
3
+ import { observer } from '@formily/react';
4
+ import { FormItem, Input, SchemaComponent, useApp } from '@nocobase/client';
5
+ import { Card, Space, message } from 'antd';
6
+ import React, { useMemo } from 'react';
7
+ import { lang, useOidcTranslation } from './locale';
8
+
9
+ const schema = {
10
+ type: 'object',
11
+ properties: {
12
+ public: {
13
+ type: 'object',
14
+ properties: {
15
+ autoSignup: {
16
+ 'x-decorator': 'FormItem',
17
+ type: 'boolean',
18
+ title: '{{t("Sign up automatically when the user does not exist")}}',
19
+ 'x-component': 'Checkbox',
20
+ default: true,
21
+ },
22
+ },
23
+ },
24
+ oidc: {
25
+ type: 'object',
26
+ properties: {
27
+ collapse: {
28
+ type: 'void',
29
+ 'x-component': 'FormTab',
30
+ properties: {
31
+ basic: {
32
+ type: 'void',
33
+ 'x-component': 'FormTab.TabPane',
34
+ 'x-component-props': {
35
+ tab: lang('Basic configuration'),
36
+ },
37
+ properties: {
38
+ issuer: {
39
+ type: 'string',
40
+ title: '{{t("Issuer")}}',
41
+ 'x-component': 'Input',
42
+ 'x-decorator': 'FormItem',
43
+ required: true,
44
+ },
45
+ clientId: {
46
+ type: 'string',
47
+ title: '{{t("Client ID")}}',
48
+ 'x-component': 'Input',
49
+ 'x-decorator': 'FormItem',
50
+ required: true,
51
+ },
52
+ clientSecret: {
53
+ type: 'string',
54
+ title: '{{t("Client Secret")}}',
55
+ 'x-component': 'Input',
56
+ 'x-decorator': 'FormItem',
57
+ required: true,
58
+ },
59
+ scope: {
60
+ type: 'string',
61
+ title: '{{t("scope")}}',
62
+ 'x-component': 'Input',
63
+ 'x-decorator': 'FormItem',
64
+ 'x-decorator-props': {
65
+ tooltip: '{{t("Default: openid profile email")}}',
66
+ },
67
+ },
68
+ idTokenSignedResponseAlg: {
69
+ type: 'string',
70
+ title: '{{t("id_token signed response algorithm")}}',
71
+ 'x-component': 'Select',
72
+ 'x-decorator': 'FormItem',
73
+ enum: [
74
+ { label: 'HS256', value: 'HS256' },
75
+ { label: 'HS384', value: 'HS384' },
76
+ { label: 'HS512', value: 'HS512' },
77
+ { label: 'RS256', value: 'RS256' },
78
+ { label: 'RS384', value: 'RS384' },
79
+ { label: 'RS512', value: 'RS512' },
80
+ { label: 'ES256', value: 'ES256' },
81
+ { label: 'ES384', value: 'ES384' },
82
+ { label: 'ES512', value: 'ES512' },
83
+ { label: 'PS256', value: 'PS256' },
84
+ { label: 'PS384', value: 'PS384' },
85
+ { label: 'PS512', value: 'PS512' },
86
+ ],
87
+ },
88
+ },
89
+ },
90
+ mapping: {
91
+ type: 'void',
92
+ 'x-component': 'FormTab.TabPane',
93
+ 'x-component-props': {
94
+ tab: lang('Field mapping'),
95
+ },
96
+ properties: {
97
+ fieldMap: {
98
+ title: '{{t("Field Map")}}',
99
+ type: 'array',
100
+ 'x-decorator': 'FormItem',
101
+ 'x-component': 'ArrayItems',
102
+ items: {
103
+ type: 'object',
104
+ 'x-decorator': 'ArrayItems.Item',
105
+ properties: {
106
+ space: {
107
+ type: 'void',
108
+ 'x-component': 'Space',
109
+ properties: {
110
+ source: {
111
+ type: 'string',
112
+ 'x-decorator': 'FormItem',
113
+ 'x-component': 'Input',
114
+ 'x-component-props': {
115
+ placeholder: '{{t("source")}}',
116
+ },
117
+ },
118
+ target: {
119
+ type: 'string',
120
+ 'x-decorator': 'FormItem',
121
+ 'x-component': 'Input',
122
+ 'x-component-props': {
123
+ placeholder: '{{t("target")}}',
124
+ },
125
+ },
126
+ remove: {
127
+ type: 'void',
128
+ 'x-decorator': 'FormItem',
129
+ 'x-component': 'ArrayItems.Remove',
130
+ },
131
+ },
132
+ },
133
+ },
134
+ },
135
+ properties: {
136
+ add: {
137
+ type: 'void',
138
+ title: 'Add',
139
+ 'x-component': 'ArrayItems.Addition',
140
+ },
141
+ },
142
+ },
143
+ userBindField: {
144
+ type: 'string',
145
+ title: '{{t("Use this field to bind the user")}}',
146
+ 'x-component': 'Select',
147
+ 'x-decorator': 'FormItem',
148
+ default: 'email',
149
+ enum: [
150
+ { label: lang('Email'), value: 'email' },
151
+ { label: lang('Username'), value: 'username' },
152
+ ],
153
+ required: true,
154
+ },
155
+ },
156
+ },
157
+ advanced: {
158
+ type: 'void',
159
+ 'x-component': 'FormTab.TabPane',
160
+ 'x-component-props': {
161
+ tab: lang('Advanced configuration'),
162
+ },
163
+ properties: {
164
+ logout: {
165
+ type: 'boolean',
166
+ title: '{{t("RP-initiated logout")}}',
167
+ 'x-component': 'Checkbox',
168
+ 'x-decorator': 'FormItem',
169
+ 'x-decorator-props': {
170
+ tooltip:
171
+ '{{t("Performs logout on the issuer (uses end_session_endpoint in the issuer configuration)")}}',
172
+ },
173
+ },
174
+ http: {
175
+ type: 'boolean',
176
+ title: '{{t("HTTP")}}',
177
+ 'x-component': 'Checkbox',
178
+ 'x-decorator': 'FormItem',
179
+ 'x-decorator-props': {
180
+ tooltip: '{{t("Check if NocoBase is running on HTTP protocol")}}',
181
+ },
182
+ },
183
+ port: {
184
+ type: 'number',
185
+ title: '{{t("Port")}}',
186
+ 'x-component': 'InputNumber',
187
+ 'x-decorator': 'FormItem',
188
+ 'x-decorator-props': {
189
+ tooltip: '{{t("The port number of the NocoBase service if it is not 80 or 443")}}',
190
+ },
191
+ 'x-component-props': {
192
+ style: {
193
+ width: '15%',
194
+ minWidth: '100px',
195
+ },
196
+ },
197
+ },
198
+ stateToken: {
199
+ type: 'string',
200
+ title: '{{t("State token")}}',
201
+ 'x-component': 'Input',
202
+ 'x-decorator': 'FormItem',
203
+ description: lang(
204
+ "The state token helps prevent CSRF attacks. It's recommended to leave it blank for automatic random generation.",
205
+ ),
206
+ },
207
+ exchangeBodyKeys: {
208
+ type: 'array',
209
+ title: '{{t("Pass parameters in the authorization code grant exchange")}}',
210
+ 'x-decorator': 'FormItem',
211
+ 'x-component': 'ArrayItems',
212
+ default: [
213
+ { paramName: '', optionsKey: 'clientId' },
214
+ {
215
+ paramName: '',
216
+ optionsKey: 'clientSecret',
217
+ },
218
+ ],
219
+ items: {
220
+ type: 'object',
221
+ 'x-decorator': 'ArrayItems.Item',
222
+ properties: {
223
+ space: {
224
+ type: 'void',
225
+ 'x-component': 'Space',
226
+ properties: {
227
+ enabled: {
228
+ type: 'boolean',
229
+ 'x-decorator': 'FormItem',
230
+ 'x-component': 'Checkbox',
231
+ },
232
+ optionsKey: {
233
+ type: 'string',
234
+ 'x-decorator': 'FormItem',
235
+ 'x-decorator-props': {
236
+ style: {
237
+ width: '100px',
238
+ },
239
+ },
240
+ 'x-component': 'Select',
241
+ 'x-read-pretty': true,
242
+ enum: [
243
+ { label: lang('Client ID'), value: 'clientId' },
244
+ { label: lang('Client Secret'), value: 'clientSecret' },
245
+ ],
246
+ },
247
+ paramName: {
248
+ type: 'string',
249
+ 'x-decorator': 'FormItem',
250
+ 'x-component': 'Input',
251
+ 'x-component-props': {
252
+ placeholder: '{{t("Parameter name")}}',
253
+ },
254
+ },
255
+ },
256
+ },
257
+ },
258
+ },
259
+ },
260
+ userInfoMethod: {
261
+ type: 'string',
262
+ title: '{{t("Method to call the user info endpoint")}}',
263
+ 'x- decorator': 'FormItem',
264
+ 'x-component': 'Radio.Group',
265
+ default: 'GET',
266
+ enum: [
267
+ {
268
+ label: 'GET',
269
+ value: 'GET',
270
+ },
271
+ {
272
+ label: 'POST',
273
+ value: 'POST',
274
+ },
275
+ ],
276
+ 'x-reactions': [
277
+ {
278
+ dependencies: ['.accessTokenVia'],
279
+ when: '{{$deps[0] === "query"}}',
280
+ fulfill: {
281
+ state: {
282
+ value: 'GET',
283
+ },
284
+ },
285
+ },
286
+ {
287
+ dependencies: ['.accessTokenVia'],
288
+ when: '{{$deps[0] === "body"}}',
289
+ fulfill: {
290
+ state: {
291
+ value: 'POST',
292
+ },
293
+ },
294
+ },
295
+ ],
296
+ },
297
+ accessTokenVia: {
298
+ type: 'string',
299
+ title: '{{t("Where to put the access token when calling the user info endpoint")}}',
300
+ 'x- decorator': 'FormItem',
301
+ 'x-component': 'Radio.Group',
302
+ default: 'header',
303
+ enum: [
304
+ {
305
+ label: lang('Header'),
306
+ value: 'header',
307
+ },
308
+ {
309
+ label: lang('Body (Use with POST method)'),
310
+ value: 'body',
311
+ },
312
+ {
313
+ label: lang('Query parameters (Use with GET method)'),
314
+ value: 'query',
315
+ },
316
+ ],
317
+ },
318
+ },
319
+ },
320
+ },
321
+ },
322
+ },
323
+ },
324
+ usage: {
325
+ type: 'void',
326
+ 'x-component': 'Usage',
327
+ },
328
+ },
329
+ };
330
+
331
+ const Usage = observer(
332
+ () => {
333
+ const { t } = useOidcTranslation();
334
+ const app = useApp();
335
+
336
+ const url = useMemo(() => {
337
+ return app.getApiUrl('oidc:redirect');
338
+ }, [app]);
339
+
340
+ const copy = (text: string) => {
341
+ navigator.clipboard.writeText(text);
342
+ message.success(t('Copied'));
343
+ };
344
+
345
+ return (
346
+ <Card title={t('Usage')} type="inner">
347
+ <FormItem label={t('Redirect URL')}>
348
+ <Input value={url} disabled={true} addonBefore={<CopyOutlined onClick={() => copy(url)} />} />
349
+ </FormItem>
350
+ </Card>
351
+ );
352
+ },
353
+ { displayName: 'Usage' },
354
+ );
355
+
356
+ export const Options = () => {
357
+ const { t } = useOidcTranslation();
358
+ return <SchemaComponent scope={{ t }} components={{ Usage, ArrayItems, Space, FormTab }} schema={schema} />;
359
+ };
@@ -0,0 +1,19 @@
1
+ import { Plugin } from '@nocobase/client';
2
+ import AuthPlugin from '@nocobase/plugin-auth/client';
3
+ import { authType } from '../constants';
4
+ import { OIDCButton } from './OIDCButton';
5
+ import { Options } from './Options';
6
+
7
+ export class PluginOIDCClient extends Plugin {
8
+ async load() {
9
+ const auth = this.app.pm.get(AuthPlugin);
10
+ auth.registerType(authType, {
11
+ components: {
12
+ SignInButton: OIDCButton,
13
+ AdminSettingsForm: Options,
14
+ },
15
+ });
16
+ }
17
+ }
18
+
19
+ export default PluginOIDCClient;
@@ -0,0 +1,18 @@
1
+ import { i18n } from '@nocobase/client';
2
+ import { useTranslation } from 'react-i18next';
3
+
4
+ export const NAMESPACE = 'oidc';
5
+
6
+ // i18n.addResources('zh-CN', NAMESPACE, zhCN);
7
+ // i18n.addResources('en-US', NAMESPACE, enUS);
8
+ // i18n.addResources('ja-JP', NAMESPACE, jaJP);
9
+ // i18n.addResources('ru-RU', NAMESPACE, ruRU);
10
+ // i18n.addResources('tr-TR', NAMESPACE, trTR);
11
+
12
+ export function lang(key: string) {
13
+ return i18n.t(key, { ns: NAMESPACE });
14
+ }
15
+
16
+ export function useOidcTranslation() {
17
+ return useTranslation(NAMESPACE);
18
+ }
@@ -0,0 +1,7 @@
1
+ // @ts-ignore
2
+ import { name } from '../package.json';
3
+
4
+ export const authType = 'OIDC+';
5
+ export const cookieName = 'tnp_oidc_plus';
6
+ export const logoutCookieName = 'tnp_oidc_plus_logout';
7
+ export const namespace = name;
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './server';
2
+ export { default } from './server';