UNPKG

dnp-client

Version:

数据基础设施轻量连接器,帮助用户管理身份凭证、区域节点、业务节点,完成身份集成。

2 lines (1 loc) 16.2 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("uuid");class i{constructor(t={}){const{options:s={},callbacks:o={}}=t;this.options={pollingTimeout:6e5,pollingInterval:1e3,dnpServerUrl:"http://localhost:3521",certificate:"",requestTimeout:6e4,apiEndpoints:{getAuthResult:"/get/authResult",getToken:"/get/token",getCert:"/get/cert",importCert:"/import/cert",createCert:"/create/cert"},baseUrl:"undefined"!=typeof window?`${window.location.origin}/api/v1`:"",type:1,clientType:i.detectClientType(),...s},this.uuidString="",this.startTime=0,this.isPolling=!1,this.pollingTimer=null,this.callbacks={onLoading:t=>{},onSuccess:t=>{},onError:t=>{},onMessage:(t,i="info")=>{},...o},this.login=this.login.bind(this),this.stopPolling=this.stopPolling.bind(this),this.clickAuthLogin=this.clickAuthLogin.bind(this),this.registerIdentity=this.registerIdentity.bind(this),this.importCert=this.importCert.bind(this)}static detectClientType(){return"undefined"==typeof window?"server":"function"==typeof window.sendToMain?"electron":"browser"}static getBrowserInfo(){if("undefined"==typeof window||!window.navigator)return"unknown";const{userAgent:t}=window.navigator;let i="unknown";return t.indexOf("Chrome")>-1&&-1===t.indexOf("Edg")?i="Chrome":t.indexOf("Firefox")>-1?i="Firefox":t.indexOf("Safari")>-1&&-1===t.indexOf("Chrome")?i="Safari":t.indexOf("Edg")>-1?i="Edge":t.indexOf("Opera")>-1||t.indexOf("OPR")>-1?i="Opera":(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(i="IE"),i}async login(){try{this.stopPolling(),this.callbacks.onLoading(!0),await this.clickAuthLogin()}catch(t){this.callbacks.onError(t),this.callbacks.onLoading(!1)}}async clickAuthLogin(){if(!this.options.nodeId){const t={message:"身份认证失败(JS1001),请联系您当前要登录的平台方进行处理",data:{message:"缺少必需参数:nodeId"}};throw this.callbacks.onError(t),this.callbacks.onMessage("身份认证失败(JS1001),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),t}if("string"!=typeof this.options.nodeId){const t={message:"身份认证失败(JS1002),请联系您当前要登录的平台方进行处理",data:{message:"nodeId 参数值无效,必须是字符串",data:this.options.nodeId}};throw this.callbacks.onError(t),this.callbacks.onMessage("身份认证失败(JS1002),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),t}this.uuidString=t.v7().slice(0,32),this.invokeDesktopApp(`dnp://getToken?json=${JSON.stringify({uuid:this.uuidString,nodeId:this.options.nodeId,browser:i.getBrowserInfo()})}`,async()=>{this.invokeDesktopAppLogin()})}invokeDesktopApp(t,i){try{const s=document.createElement("iframe");s.style.display="none",s.src=t,document.body.appendChild(s),setTimeout(()=>{document.body.removeChild(s)},1e3),i&&"function"==typeof i&&i()}catch(t){this.callbacks.onError(t),this.callbacks.onLoading(!1)}}invokeDesktopAppLogin(){this.stopPolling(),this.startTime=Date.now(),this.isPolling=!0,this.waitForResult()}async waitForResult(){if(this.isPolling){if(Date.now()-this.startTime>=this.options.pollingTimeout)return this.stopPolling(),this.callbacks.onMessage("获取认证结果失败","error"),void this.callbacks.onLoading(!1);try{const t=await this.apiGetAuthResult(this.uuidString);if(t){if("refuse"===t)return this.stopPolling(),this.callbacks.onMessage("客户端正忙,请稍后再试","error"),void this.callbacks.onLoading(!1);if(t.data){if(t.data?.success)return this.stopPolling(),this.callbacks.onSuccess(),void this.callbacks.onLoading(!1);if(!t.data?.success)return this.stopPolling(),this.callbacks.onError(t.data),void this.callbacks.onLoading(!1)}return void(this.pollingTimer=setTimeout(()=>{this.waitForResult()},this.options.pollingInterval))}this.pollingTimer=setTimeout(()=>{this.waitForResult()},this.options.pollingInterval)}catch(t){if("CORS"===t.type)return this.stopPolling(),this.callbacks.onMessage("请求失败(JS5001),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onError({message:"请求失败(JS5001),请联系您当前要登录的平台方进行处理"}),void this.callbacks.onLoading(!1);this.pollingTimer=setTimeout(()=>{this.waitForResult()},this.options.pollingInterval)}}}async fetchToken(t){if(!t){throw{message:"获取token失败(JS2001),请联系您当前要登录的平台方进行处理",data:{message:"缺少必需参数:uuid"}}}const i=await this.apiGetToken(t);if("refuse"===i){throw{message:"客户端正忙,请稍后再试"}}if(i.data?.tokenValue)return i.data.tokenValue;throw{message:i.data?.message||"获取token失败"}}async waitForVP(){if(this.isPolling){if(Date.now()-this.startTime>=this.options.pollingTimeout)return this.stopPolling(),this.callbacks.onMessage("获取签名失败","error"),void this.callbacks.onLoading(!1);try{const t=await this.apiGetToken(this.options.uuidString);if(t){if("refuse"===t)return this.stopPolling(),this.callbacks.onMessage("客户端正忙,请稍后再试","error"),void this.callbacks.onLoading(!1);if(t.data){if(t.data?.tokenValue)return this.stopPolling(),this.callbacks.onSuccess(t.data.tokenValue),void this.callbacks.onLoading(!1);if(!t.data?.tokenValue)return this.stopPolling(),this.callbacks.onError(t.data),void this.callbacks.onLoading(!1)}return void(this.pollingTimer=setTimeout(()=>{this.waitForVP()},this.options.pollingInterval))}this.pollingTimer=setTimeout(()=>{this.waitForVP()},this.options.pollingInterval)}catch(t){if("CORS"===t.type)return this.stopPolling(),this.callbacks.onMessage("请求失败(JS5001),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onError({message:"请求失败(JS5001),请联系您当前要登录的平台方进行处理"}),void this.callbacks.onLoading(!1);this.pollingTimer=setTimeout(()=>{this.waitForVP()},this.options.pollingInterval)}}}stopPolling(){this.isPolling=!1,this.pollingTimer&&(clearTimeout(this.pollingTimer),this.pollingTimer=null)}async fetchWithErrorHandling(t,i={},s=""){const o=new AbortController,e=setTimeout(()=>{o.abort()},this.options.requestTimeout);try{const s=await fetch(t,{...i,signal:o.signal});if(clearTimeout(e),!s.ok){throw{message:"请求失败(JS1004),请联系您当前要登录的平台方进行处理",data:{message:"请求失败",data:s,url:t}}}return await s.json()}catch(i){clearTimeout(e);let o=s||"请求失败",n="error";const a=i?.message||i?.toString()||String(i),r=i?.name||"";"AbortError"===r||"TimeoutError"===r?(o=`请求超时,请检查网络连接或稍后重试,请求地址:${t}`,n="error"):"TypeError"===r&&(a.includes("Failed to fetch")||a.includes("NetworkError")||a.includes("Network request failed"))?(o=`网络请求失败,可能是跨域问题或服务器未响应,请检查网络连接和服务器配置,请求地址:${t}`,n="CORS"):a.includes("CORS")?(o=`跨域请求被阻止,请检查服务器CORS配置或联系管理员,请求地址:${t}`,n="CORS"):a&&"[object Object]"!==a?(o=`${a},请求地址:${t}`,n="error"):o=`${o},请求地址:${t}`;const l={message:o,originalError:i,status:i?.status,type:n,url:t};throw this.callbacks.onMessage&&this.callbacks.onMessage(o,n),l}}async apiGetAuthResult(t){const i=`${this.options.dnpServerUrl}${this.options.apiEndpoints.getAuthResult}?uuid=${t}`;return this.fetchWithErrorHandling(i,{method:"GET",headers:{"Content-Type":"application/json"}},"身份认证失败(JS1004),联系您当前要登录的平台方进行处理")}async apiGetToken(t){const i=`${this.options.dnpServerUrl}${this.options.apiEndpoints.getToken}?uuid=${t}`;return this.fetchWithErrorHandling(i,{method:"GET",headers:{"Content-Type":"application/json"}},"获取令牌失败(JS2002),请联系您当前要登录的平台方进行处理")}async createCertificate(){try{const t=`${this.options.dnpServerUrl}${this.options.apiEndpoints.createCert}`;return await this.fetchWithErrorHandling(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({certificate:this.options.certificate})},"身份注册失败(JS3008),请联系您当前要登录的平台方进行处理")}catch(t){throw this.callbacks.onError(t),this.callbacks.onLoading(!1),t}}async registerIdentity(t={}){try{if(this.stopPolling(),this.callbacks.onLoading(!0),!t.certType){const t={message:"身份注册失败(JS3001),请联系您当前要登录的平台方进行处理",data:{message:"缺少必需参数:certType"}};throw this.callbacks.onError(t),this.callbacks.onMessage("身份注册失败(JS3001),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),t}if(!["1","2","3"].includes(t.certType)){const i={message:"身份注册失败(JS3002),请联系您当前要登录的平台方进行处理",data:{message:'certType 参数值无效,必须是 "1"、"2" 或 "3"',data:t.certType}};throw this.callbacks.onError(i),this.callbacks.onMessage("身份注册失败(JS3002),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),i}if(!t.subject){const i={message:"身份注册失败(JS3003),请联系您当前要登录的平台方进行处理",data:{message:"缺少必需参数:subject",data:t.subject}};throw this.callbacks.onError(i),this.callbacks.onMessage("身份注册失败(JS3003),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),i}let i;try{if(i="string"==typeof t.subject?JSON.parse(t.subject):t.subject,Array.isArray(i)){const t={};i.forEach(i=>{i&&"object"==typeof i&&i.name&&i.value&&(t[i.name]=i.value)}),i=t}}catch(i){const s={message:"身份注册失败(JS3004),请联系您当前要登录的平台方进行处理",data:{message:"subject 参数必须是有效的 JSON 字符串格式或数组格式",data:t.subject}};throw this.callbacks.onError(s),this.callbacks.onMessage("身份注册失败(JS3004),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),s}if(!i.O){const i={message:"身份注册失败(JS3005),请联系您当前要登录的平台方进行处理",data:{message:"subject 中缺少必填字段:O(企业名称)",data:t.subject}};throw this.callbacks.onError(i),this.callbacks.onMessage("身份注册失败(JS3005),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),i}if(!i.C){const i={message:"身份注册失败(JS3006),请联系您当前要登录的平台方进行处理",data:{message:"subject 中缺少必填字段:C(国家代码)",data:t.subject}};throw this.callbacks.onError(i),this.callbacks.onMessage("身份注册失败(JS3006),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),i}if(("2"===t.certType||"3"===t.certType)&&!i.OU){const i={message:"身份注册失败(JS3007),请联系您当前要登录的平台方进行处理",data:{message:"subject 中缺少必填字段:OU(所属主体的标识)。连接器身份和业务节点身份必须提供 OU 字段",data:t.subject}};throw this.callbacks.onError(i),this.callbacks.onMessage("身份注册失败(JS3007),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onLoading(!1),i}const s="string"==typeof t.subject?t.subject:JSON.stringify(i);await this.invokeDesktopAppRegister(t.certType,s,t.didMethod)}catch(t){this.callbacks.onError(t),this.callbacks.onLoading(!1)}}async invokeDesktopAppRegister(i,s,o){this.uuidString=t.v7().slice(0,32);const e={uuid:this.uuidString,certType:i,subject:s};o&&(e.didMethod=o),"electron"!==this.options.clientType?this.invokeDesktopApp(`dnp://genKeys?json=${JSON.stringify(e)}`,()=>this.invokeDesktopAppRegisterFlow()):"function"==typeof window.sendToMain?(window.sendToMain({type:"register",data:e}),this.invokeDesktopAppRegisterFlow()):(this.callbacks.onMessage("身份注册暂时不可用,请使用其他方式","error"),this.callbacks.onLoading(!1))}invokeDesktopAppRegisterFlow(){this.stopPolling(),this.startTime=Date.now(),this.isPolling=!0,this.waitForDid()}async waitForDid(){if(this.isPolling){if(Date.now()-this.startTime>=this.options.pollingTimeout)return this.stopPolling(),this.callbacks.onMessage("身份注册超时","error"),void this.callbacks.onLoading(!1);try{const t=await this.apiGetCert("uuid",this.uuidString);if(t){if("refuse"===t)return this.stopPolling(),this.callbacks.onMessage("客户端正忙,请稍后再试","error"),void this.callbacks.onLoading(!1);if(t.data){this.stopPolling();const i=t.data;return this.callbacks.onSuccess(i),void this.callbacks.onLoading(!1)}}Date.now()-this.startTime<this.options.pollingTimeout?this.pollingTimer=setTimeout(()=>{this.waitForDid()},this.options.pollingInterval):(this.stopPolling(),this.callbacks.onMessage("身份注册超时","error"),this.callbacks.onLoading(!1))}catch(t){if("CORS"===t.type)return this.stopPolling(),this.callbacks.onMessage("请求失败(JS5001),请联系您当前要登录的平台方进行处理","error"),this.callbacks.onError({message:"请求失败(JS5001),请联系您当前要登录的平台方进行处理"}),void this.callbacks.onLoading(!1);Date.now()-this.startTime<this.options.pollingTimeout?this.pollingTimer=setTimeout(()=>{this.waitForDid()},this.options.pollingInterval):(this.stopPolling(),this.callbacks.onMessage("身份注册超时","error"),this.callbacks.onLoading(!1))}}}async apiGetCert(t,i){const s=`${this.options.dnpServerUrl}${this.options.apiEndpoints.getCert}?key=${t}&code=${i}`;return this.fetchWithErrorHandling(s,{method:"GET",headers:{"Content-Type":"application/json"}},"身份注册失败(JS3008),请联系您当前要登录的平台方进行处理")}async importCert(t){try{this.stopPolling(),this.callbacks.onLoading(!0),await this.invokeDesktopAppImportVc(t)}catch(t){this.callbacks.onError(t),this.callbacks.onLoading(!1)}}async invokeDesktopAppImportVc(t){"electron"!==this.options.clientType?this.invokeDesktopApp("dnp://import-vc",()=>this.invokeDesktopAppImportVcFlow(t)):"function"==typeof window.sendToMain?(window.sendToMain({type:"importCert",data:t}),this.invokeDesktopAppImportVcFlow(t)):(this.callbacks.onMessage("身份凭证导入暂时不可用,请使用其他方式","error"),this.callbacks.onLoading(!1))}invokeDesktopAppImportVcFlow(t){this.stopPolling(),this.startTime=Date.now(),this.isPolling=!0,this.pushVCToClient(t)}async pushVCToClient(t){if(this.isPolling){if(Date.now()-this.startTime>=this.options.pollingTimeout)return this.stopPolling(),this.callbacks.onMessage("VC导入超时","error"),void this.callbacks.onLoading(!1);try{const i=await this.apiPushCert(t);if(i){if("refuse"===i)return this.stopPolling(),this.callbacks.onMessage("客户端正忙,请稍后再试","error"),void this.callbacks.onLoading(!1);if(i.data)return this.stopPolling(),this.callbacks.onMessage("VC导入成功","success"),this.callbacks.onSuccess(i),void this.callbacks.onLoading(!1)}Date.now()-this.startTime<this.options.pollingTimeout?this.pollingTimer=setTimeout(()=>{this.isPolling&&this.pushVCToClient(t)},this.options.pollingInterval):(this.stopPolling(),this.callbacks.onMessage("VC导入超时","error"),this.callbacks.onLoading(!1))}catch(i){Date.now()-this.startTime<this.options.pollingTimeout?this.pollingTimer=setTimeout(()=>{this.isPolling&&this.pushVCToClient(t)},this.options.pollingInterval):(this.stopPolling(),this.callbacks.onMessage("VC导入失败","error"),this.callbacks.onLoading(!1))}}}async apiPushCert(t){const i=`${this.options.dnpServerUrl}${this.options.apiEndpoints.importCert}`;return this.fetchWithErrorHandling(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)},"身份凭证导入失败(JS4003),请联系您当前要登录的平台方进行处理")}destroy(){this.stopPolling(),this.callbacks={}}}exports.createDnpImportVc=function(t={}){return new i(t)},exports.createDnpLogin=function(t={}){return new i(t)},exports.createDnpRegister=function(t={}){return new i(t)},exports.createFetchToken=function(t={}){return new i(t)},exports.default=i;