@gandalan/weblibs 0.0.40 → 1.0.0

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/api/IDAS.js CHANGED
@@ -2,133 +2,155 @@ import { RESTClient } from './RESTClient';
2
2
 
3
3
  let appToken = localStorage.getItem('IDAS_AppToken') || '66B70E0B-F7C4-4829-B12A-18AD309E3970';
4
4
  let authToken = localStorage.getItem('IDAS_AuthToken');
5
- let authJwtToken = localStorage.getItem('IDAS_AuthJwtToken');
6
5
  let apiBaseUrl = localStorage.getItem('IDAS_ApiBaseUrl') || 'https://api.dev.idas-cloudservices.net/api/';
6
+ let authJwtCallbackPath = localStorage.getItem('IDAS_AuthJwtCallbackPath') || '';
7
+ let authJwtToken;
7
8
 
8
- let restClient = new RESTClient(apiBaseUrl, authToken);
9
- restClient.onError = (error, message) => {
10
- if (message.indexOf("401") != -1 || message.indexOf("403") != -1) {
11
- localStorage.removeItem('IDAS_AuthToken');
12
- localStorage.removeItem('IDAS_AuthJwtToken');
13
- new IDAS().authenticateWithSSO(true);
14
- }
15
- }
9
+ export let IDASFactory = {
10
+ async create() {
11
+ return new Promise((resolve, reject) => {
12
+ let idas = new IDAS();
13
+ resolve(idas.authenticateWithJwt(authJwtCallbackPath));
14
+ });
15
+ },
16
16
 
17
- export class IDAS {
18
- async authenticate(authDTO) {
19
- authDTO.AppToken = appToken;
20
- let { data } = await restClient.post('/Login/Authenticate', authDTO);
21
- if (data?.Token) {
22
- authToken = data.Token;
23
- localStorage.setItem('IDAS_AuthToken', authToken);
24
- restClient = new RESTClient(apiBaseUrl, authToken);
17
+ authorize() {
18
+ var urlParams = new URLSearchParams(location.search);
19
+ if (urlParams.has('t')) {
20
+ let idas = new IDAS();
21
+ idas.authorizeWithJwt(urlParams.get('t'));
22
+ }
23
+ if (urlParams.has("m")) {
24
+ localStorage.setItem("IDAS_MandantGuid", urlParams.get("m"));
25
+ }
26
+ if (urlParams.has("a")) {
27
+ localStorage.setItem("IDAS_ApiBaseUrl", urlParams.get("a"));
25
28
  }
26
- return data;
29
+ window.location.search = "";
27
30
  }
31
+ }
28
32
 
29
- async authenticateWithSSO(forceRenew = false) {
30
- if (!authToken)
31
- {
32
- const url = new URL(apiBaseUrl);
33
- url.pathname = "/SSO";
34
- url.search = "?a=" + appToken;
35
- if (forceRenew)
36
- url.search = url.search + "&forceRenew=true";
37
- url.search = url.search + "&r=%target%%3Ft=%token%%26m=%mandant%";
38
- let ssoAuthUrl = url.toString();
33
+ class IDAS {
34
+ restClient = undefined;
39
35
 
40
- var ssoURL = ssoAuthUrl.replace("%target%", encodeURIComponent(window.location.href));
41
- window.location = ssoURL;
42
- }
36
+ authorizeWithJwt(jwtToken, mandant = '') {
37
+ authJwtToken = jwtToken;
38
+ mandant && localStorage.setItem('IDAS_MandantGuid', mandant);
39
+ this.restClient = new RESTClient(apiBaseUrl, jwtToken, true);
43
40
  }
44
41
 
45
- async authenticateWithJwt() {
46
- if (!authJwtToken) {
47
- const url = new URL(apiBaseUrl);
48
- url.pathname = "/Session";
49
- url.search = "?a=" + appToken;
50
- url.search = url.search + "&r=%target%";
51
- let jwtAuthUrl = url.toString();
42
+ async authenticateWithJwt(authPath) {
43
+ return new Promise(async (resolve, reject) => {
44
+ // no valid JWT, but try to use "refresh token" first to retrive new JWT
45
+ var refreshClient = new RESTClient(apiBaseUrl, '');
46
+ await refreshClient.checkRefreshToken(authJwtToken, () => {
47
+ authJwtToken = undefined;
48
+ // ... so repeat authenticate (should lead to /Session login page)
49
+ new IDAS().authenticateWithJwt(authPath);
50
+ });
52
51
 
53
- var jwtUrl = jwtAuthUrl.replace("%target%", encodeURIComponent(window.location.href));
54
- window.location = jwtUrl;
55
- }
52
+ // still not valid JWT -> authenticate
53
+ if (!refreshClient.token) {
54
+ localStorage.setItem('IDAS_AuthJwtCallbackPath', authPath);
55
+ const authEndpoint = (new URL(window.location.href).origin) + authPath;
56
+ let authUrlCallback = `${authEndpoint}?r=%target%&t=%jwt%&m=%mandant%`;
57
+ authUrlCallback = authUrlCallback.replace('%target%', encodeURIComponent(window.location.href));
58
+
59
+ const url = new URL(apiBaseUrl);
60
+ url.pathname = "/Session";
61
+ url.search = `?a=${appToken}&r=${encodeURIComponent(authUrlCallback)}`;
62
+ let jwtUrl = url.toString();
63
+
64
+ window.location = jwtUrl;
65
+ reject('not authenticated yet');
66
+ } else {
67
+ this.authorizeWithJwt(refreshClient.token);
68
+ resolve(this);
69
+ }
70
+ });
56
71
  }
57
72
 
58
73
  mandantGuid = localStorage.getItem('IDAS_MandantGuid');
59
74
 
60
75
  auth = {
76
+ _self: this,
61
77
  async getCurrentAuthToken() {
62
- return await restClient.put('/Login/Update/', { Token: authToken })
78
+ return await this._self.restClient.put('/Login/Update/', { Token: authToken })
63
79
  },
64
80
  };
65
81
 
66
82
  mandanten = {
83
+ _self: this,
67
84
  async getAll() {
68
- return await restClient.get('/Mandanten');
85
+ return await this._self.restClient.get('/Mandanten');
69
86
  },
70
87
  async get(guid) {
71
- return await restClient.get(`/Mandanten/${guid}`);
88
+ return await this._self.restClient.get(`/Mandanten/${guid}`);
72
89
  },
73
90
  async save(m) {
74
- await restClient.put('/Mandanten', m);
91
+ await this._self.restClient.put('/Mandanten', m);
75
92
  },
76
93
  };
77
94
 
78
95
  benutzer = {
96
+ _self: this,
79
97
  async getAll(mandantGuid) {
80
- return await restClient.get(`/BenutzerListe/${mandantGuid }/?mitRollenUndRechten=true`);
98
+ return await this._self.restClient.get(`/BenutzerListe/${mandantGuid }/?mitRollenUndRechten=true`);
81
99
  },
82
100
  async get(guid) {
83
- return await restClient.get(`/Benutzer/${guid}`);
101
+ return await this._self.restClient.get(`/Benutzer/${guid}`);
84
102
  },
85
103
  async save(m) {
86
- await restClient.put('/Benutzer', m);
104
+ await this._self.restClient.put('/Benutzer', m);
87
105
  },
88
106
  };
89
107
 
90
108
  feedback = {
109
+ _self: this,
91
110
  async getAll() {
92
- return await restClient.get('/Feedback/');
111
+ return await this._self.restClient.get('/Feedback/');
93
112
  },
94
113
  async get(guid) {
95
- return await restClient.get(`/Feedback/${guid}`);
114
+ return await this._self.restClient.get(`/Feedback/${guid}`);
96
115
  },
97
116
  async save(m) {
98
- await restClient.put('/Feedback', m);
117
+ await this._self.restClient.put('/Feedback', m);
99
118
  },
100
119
  async comment(guid, commentData) {
101
- await restClient.put(`/FeedbackKommentar/${guid}`, commentData);
120
+ await this._self.restClient.put(`/FeedbackKommentar/${guid}`, commentData);
102
121
  },
103
122
  async attachFile(guid, filename, data) {
104
- await restClient.put(`/FeedbackAttachment/?feedbackGuid=${guid}&filename=${filename}`, data);
123
+ await this._self.restClient.put(`/FeedbackAttachment/?feedbackGuid=${guid}&filename=${filename}`, data);
105
124
  },
106
125
  async deleteFile(guid) {
107
- await restClient.delete(`/FeedbackAttachment/${guid}`);
126
+ await this._self.restClient.delete(`/FeedbackAttachment/${guid}`);
108
127
  },
109
128
  };
110
129
 
111
130
  rollen = {
131
+ _self: this,
112
132
  async getAll() {
113
- return await restClient.get('/Rollen');
133
+ return await this._self.restClient.get('/Rollen');
114
134
  },
115
135
  async save(m) {
116
- await restClient.put('/Rollen', m);
136
+ await this._self.restClient.put('/Rollen', m);
117
137
  },
118
138
  };
119
139
 
120
140
  vorgaenge = {
141
+ _self: this,
121
142
  async getByVorgangsnummer(vorgangsNummer, jahr) {
122
- return await restClient.get(`/Vorgang/${vorgangsNummer}/${jahr}`);
143
+ return await this._self.restClient.get(`/Vorgang/${vorgangsNummer}/${jahr}`);
123
144
  },
124
145
  };
125
146
 
126
147
  positionen = {
148
+ _self: this,
127
149
  async getByPcode(pcode) {
128
- return await restClient.get(`/BelegPositionen/GetByPcode/${pcode}`);
150
+ return await this._self.restClient.get(`/BelegPositionen/GetByPcode/${pcode}`);
129
151
  },
130
152
  async get(guid) {
131
- return await restClient.get(`/BelegPositionen/Get/${guid}`);
153
+ return await this._self.restClient.get(`/BelegPositionen/Get/${guid}`);
132
154
  },
133
155
  };
134
156
  }
package/api/RESTClient.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import axios from 'axios';
2
+ import jwt_decode from 'jwt-decode';
2
3
 
3
4
  /*export let AppToken = "66B70E0B-F7C4-4829-B12A-18AD309E3970";
4
5
  export let AuthToken = localStorage.getItem("AuthToken");
@@ -7,6 +8,8 @@ export let ApiBaseUrl = localStorage.getItem("ApiBaseUrl") || "https://api.dev.i
7
8
  export let SiteBaseUrl = window.location.origin;
8
9
  export let SSOAuthUrl = ApiBaseUrl.replace("/api", '') + "/SSO?a=" + AppToken + "&r=%target%?t=%token%%26m=%mandant%";*/
9
10
 
11
+ let authJwtRefreshToken = localStorage.getItem('IDAS_AuthJwtRefreshToken');
12
+
10
13
  export class RESTClient {
11
14
  lastError = '';
12
15
  token = '';
@@ -22,11 +25,85 @@ export class RESTClient {
22
25
  axios.defaults.headers.common['X-Gdl-AuthToken'] = this.token;
23
26
  }
24
27
 
25
- axios.interceptors.request.use(req => {
26
- return req;
28
+ if (this.token && isJWT) {
29
+ this.updateJwtToken(token);
30
+ }
31
+
32
+ axios.interceptors.request.use(async (config) => {
33
+ await this.checkAuthorizationHeader(config);
34
+ return config;
27
35
  });
28
36
  }
29
37
 
38
+ async checkAuthorizationHeader(config) {
39
+ let authHeader = config.headers['Authorization'];
40
+ if (authHeader && authHeader.toString().startsWith('Bearer ')) {
41
+ let parts = authHeader.toString().split(' ');
42
+ let jwt = parts[1];
43
+ if (!this.isJwtTokenExpired(jwt)) {
44
+ // JWT token is not expired
45
+ return;
46
+ }
47
+
48
+ // expired token - refresh
49
+ await this.checkRefreshToken(jwt);
50
+ }
51
+ }
52
+
53
+ async checkRefreshToken(jwt, authCallback) {
54
+ if (!jwt && authJwtRefreshToken) {
55
+ this.onError = (error, message) => {
56
+ // LoginJwt/Refresh failed, which means "refresh token" is expired/invalid...
57
+ if (message.indexOf("401") != -1 || message.indexOf("403") != -1) {
58
+ authJwtRefreshToken = undefined;
59
+ localStorage.removeItem('IDAS_AuthJwtRefreshToken');
60
+ // ... so repeat authenticate
61
+ authCallback && authCallback();
62
+ }
63
+ };
64
+ // fetch fresh JWT
65
+ await this.refreshToken();
66
+ return;
67
+ }
68
+ this.token = jwt;
69
+ this.isJWT = true;
70
+ }
71
+
72
+ isJwtTokenExpired(jwt) {
73
+ if (!jwt) {
74
+ return true;
75
+ }
76
+
77
+ let decoded = jwt_decode(jwt);
78
+ const utcNow = Date.parse(new Date().toUTCString()) / 1000;
79
+
80
+ if (decoded && decoded.exp >= utcNow) {
81
+ return false;
82
+ }
83
+
84
+ return true;
85
+ }
86
+
87
+ updateJwtToken(jwt) {
88
+ let decoded = jwt_decode(jwt);
89
+ let refreshToken = decoded['refreshToken'];
90
+ localStorage.setItem('IDAS_AuthJwtRefreshToken', refreshToken);
91
+ authJwtRefreshToken = refreshToken;
92
+ this.token = jwt;
93
+ this.isJWT = true;
94
+ }
95
+
96
+ async refreshToken() {
97
+ try {
98
+ await axios.put(this.baseurl + '/LoginJwt/Refresh', { token: localStorage.getItem('IDAS_AuthJwtRefreshToken') })
99
+ .then(resp => {
100
+ this.updateJwtToken(resp.data);
101
+ });
102
+ } catch (error) {
103
+ this.handleError(error);
104
+ }
105
+ }
106
+
30
107
  updateToken(token) {
31
108
  this.token = token;
32
109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gandalan/weblibs",
3
- "version": "0.0.40",
3
+ "version": "1.0.0",
4
4
  "description": "WebLibs for Gandalan JS/TS/Svelte projects",
5
5
  "author": "Philipp Reif",
6
6
  "license": "ISC",
@@ -23,6 +23,7 @@
23
23
  "dependencies": {
24
24
  "@mdi/js": "^7.0.96",
25
25
  "axios": "^0.27.2",
26
+ "jwt-decode": "^3.1.2",
26
27
  "svelte-table": "^0.5.1"
27
28
  },
28
29
  "peerDependencies": {