@itwin/core-electron 3.0.0-extension.1 → 3.1.0-dev.6

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 (31) hide show
  1. package/CHANGELOG.md +76 -1
  2. package/LICENSE.md +1 -1
  3. package/lib/cjs/ElectronBackend.d.ts +0 -1
  4. package/lib/cjs/ElectronBackend.d.ts.map +1 -1
  5. package/lib/cjs/ElectronBackend.js +0 -1
  6. package/lib/cjs/ElectronBackend.js.map +1 -1
  7. package/lib/cjs/backend/ElectronHost.d.ts +1 -9
  8. package/lib/cjs/backend/ElectronHost.d.ts.map +1 -1
  9. package/lib/cjs/backend/ElectronHost.js +1 -9
  10. package/lib/cjs/backend/ElectronHost.js.map +1 -1
  11. package/package.json +15 -16
  12. package/lib/cjs/backend/ElectronAuthorizationBackend.d.ts +0 -71
  13. package/lib/cjs/backend/ElectronAuthorizationBackend.d.ts.map +0 -1
  14. package/lib/cjs/backend/ElectronAuthorizationBackend.js +0 -265
  15. package/lib/cjs/backend/ElectronAuthorizationBackend.js.map +0 -1
  16. package/lib/cjs/backend/ElectronAuthorizationEvents.d.ts +0 -20
  17. package/lib/cjs/backend/ElectronAuthorizationEvents.d.ts.map +0 -1
  18. package/lib/cjs/backend/ElectronAuthorizationEvents.js +0 -26
  19. package/lib/cjs/backend/ElectronAuthorizationEvents.js.map +0 -1
  20. package/lib/cjs/backend/ElectronAuthorizationRequestHandler.d.ts +0 -25
  21. package/lib/cjs/backend/ElectronAuthorizationRequestHandler.d.ts.map +0 -1
  22. package/lib/cjs/backend/ElectronAuthorizationRequestHandler.js +0 -63
  23. package/lib/cjs/backend/ElectronAuthorizationRequestHandler.js.map +0 -1
  24. package/lib/cjs/backend/ElectronTokenStore.d.ts +0 -18
  25. package/lib/cjs/backend/ElectronTokenStore.d.ts.map +0 -1
  26. package/lib/cjs/backend/ElectronTokenStore.js +0 -66
  27. package/lib/cjs/backend/ElectronTokenStore.js.map +0 -1
  28. package/lib/cjs/backend/LoopbackWebServer.d.ts +0 -19
  29. package/lib/cjs/backend/LoopbackWebServer.d.ts.map +0 -1
  30. package/lib/cjs/backend/LoopbackWebServer.js +0 -101
  31. package/lib/cjs/backend/LoopbackWebServer.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,81 @@
1
1
  # Change Log - @itwin/core-electron
2
2
 
3
- This log was last generated on Tue, 21 Sep 2021 21:06:40 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 12 Jan 2022 14:52:38 GMT and should not be manually modified.
4
+
5
+ ## 2.19.28
6
+ Wed, 12 Jan 2022 14:52:38 GMT
7
+
8
+ _Version update only_
9
+
10
+ ## 2.19.27
11
+ Wed, 05 Jan 2022 20:07:20 GMT
12
+
13
+ _Version update only_
14
+
15
+ ## 2.19.26
16
+ Wed, 08 Dec 2021 20:54:52 GMT
17
+
18
+ _Version update only_
19
+
20
+ ## 2.19.25
21
+ Fri, 03 Dec 2021 20:05:49 GMT
22
+
23
+ _Version update only_
24
+
25
+ ## 2.19.24
26
+ Mon, 29 Nov 2021 18:44:31 GMT
27
+
28
+ _Version update only_
29
+
30
+ ## 2.19.23
31
+ Mon, 22 Nov 2021 20:41:39 GMT
32
+
33
+ _Version update only_
34
+
35
+ ## 2.19.22
36
+ Wed, 17 Nov 2021 01:23:26 GMT
37
+
38
+ _Version update only_
39
+
40
+ ## 2.19.21
41
+ Wed, 10 Nov 2021 10:58:24 GMT
42
+
43
+ _Version update only_
44
+
45
+ ## 2.19.20
46
+ Fri, 29 Oct 2021 16:14:22 GMT
47
+
48
+ _Version update only_
49
+
50
+ ## 2.19.19
51
+ Mon, 25 Oct 2021 16:16:25 GMT
52
+
53
+ _Version update only_
54
+
55
+ ## 2.19.18
56
+ Thu, 21 Oct 2021 20:59:44 GMT
57
+
58
+ _Version update only_
59
+
60
+ ## 2.19.17
61
+ Thu, 14 Oct 2021 21:19:43 GMT
62
+
63
+ _Version update only_
64
+
65
+ ## 2.19.16
66
+ Mon, 11 Oct 2021 17:37:46 GMT
67
+
68
+ _Version update only_
69
+
70
+ ## 2.19.15
71
+ Fri, 08 Oct 2021 16:44:23 GMT
72
+
73
+ _Version update only_
74
+
75
+ ## 2.19.14
76
+ Fri, 01 Oct 2021 13:07:03 GMT
77
+
78
+ _Version update only_
4
79
 
5
80
  ## 2.19.13
6
81
  Tue, 21 Sep 2021 21:06:40 GMT
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright © 2017-2021 Bentley Systems, Incorporated. All rights reserved.
3
+ Copyright © 2017-2022 Bentley Systems, Incorporated. All rights reserved.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
6
 
@@ -1,3 +1,2 @@
1
1
  export * from "./backend/ElectronHost";
2
- export * from "./backend/ElectronAuthorizationBackend";
3
2
  //# sourceMappingURL=ElectronBackend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ElectronBackend.d.ts","sourceRoot":"","sources":["../../src/ElectronBackend.ts"],"names":[],"mappings":"AAKA,cAAc,wBAAwB,CAAC;AACvC,cAAc,wCAAwC,CAAC"}
1
+ {"version":3,"file":"ElectronBackend.d.ts","sourceRoot":"","sources":["../../src/ElectronBackend.ts"],"names":[],"mappings":"AAKA,cAAc,wBAAwB,CAAC"}
@@ -15,5 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./backend/ElectronHost"), exports);
18
- __exportStar(require("./backend/ElectronAuthorizationBackend"), exports);
19
18
  //# sourceMappingURL=ElectronBackend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ElectronBackend.js","sourceRoot":"","sources":["../../src/ElectronBackend.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;;;;;;;;;;;;AAE/F,yDAAuC;AACvC,yEAAuD","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nexport * from \"./backend/ElectronHost\";\r\nexport * from \"./backend/ElectronAuthorizationBackend\";\r\n"]}
1
+ {"version":3,"file":"ElectronBackend.js","sourceRoot":"","sources":["../../src/ElectronBackend.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;;;;;;;;;;;;AAE/F,yDAAuC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nexport * from \"./backend/ElectronHost\";\r\n"]}
@@ -1,7 +1,6 @@
1
1
  import { BrowserWindow, BrowserWindowConstructorOptions } from "electron";
2
2
  import { IpcHandler, NativeHostOpts } from "@itwin/core-backend";
3
- import { NativeAppAuthorizationConfiguration, RpcConfiguration, RpcInterfaceDefinition } from "@itwin/core-common";
4
- import { ElectronAuthorizationBackend } from "./ElectronAuthorizationBackend";
3
+ import { RpcConfiguration, RpcInterfaceDefinition } from "@itwin/core-common";
5
4
  /**
6
5
  * Options for [[ElectronHost.startup]]
7
6
  * @beta
@@ -21,11 +20,6 @@ export interface ElectronHostOptions {
21
20
  rpcInterfaces?: RpcInterfaceDefinition[];
22
21
  /** list of [IpcHandler]($common) classes to register */
23
22
  ipcHandlers?: (typeof IpcHandler)[];
24
- /** if present, [[NativeHost.authorizationClient]] will be set to an instance of NativeAppAuthorizationBackend and will be initialized. */
25
- authConfig?: NativeAppAuthorizationConfiguration;
26
- /** if true, do not attempt to initialize AuthorizationClient on startup */
27
- noInitializeAuthClient?: boolean;
28
- applicationName?: never;
29
23
  }
30
24
  /** @beta */
31
25
  export interface ElectronHostOpts extends NativeHostOpts {
@@ -63,8 +57,6 @@ export declare class ElectronHost {
63
57
  static get ipcMain(): Electron.IpcMain;
64
58
  static get app(): Electron.App;
65
59
  static get electron(): typeof Electron;
66
- /** @internal */
67
- static get authorization(): ElectronAuthorizationBackend;
68
60
  private constructor();
69
61
  /**
70
62
  * Converts an "electron://frontend/" URL to an absolute file path.
@@ -1 +1 @@
1
- {"version":3,"file":"ElectronHost.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronHost.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAC;AAI1E,OAAO,EAAc,UAAU,EAAuB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAClG,OAAO,EAA0E,mCAAmC,EAAkB,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE3M,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAuB9E;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2IAA2I;IAC3I,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,aAAa,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACzC,wDAAwD;IACxD,WAAW,CAAC,EAAE,CAAC,OAAO,UAAU,CAAC,EAAE,CAAC;IACpC,0IAA0I;IAC1I,UAAU,CAAC,EAAE,mCAAmC,CAAC;IACjD,2EAA2E;IAC3E,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB;AAED,YAAY;AACZ,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAED,YAAY;AACZ,MAAM,WAAW,yBAA0B,SAAQ,+BAA+B;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,CAAC,SAAS,GAAG,QAAQ,GAAG,aAAa,GAAG,sBAAsB,CAAC,CAAC;CACjF;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAc;IACjC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAU;IAC3C,OAAO,CAAC,MAAM,CAAC,SAAS,CAAkB;IAC1C,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA0B;IAC1D,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAgB;IAC3C,OAAc,gBAAgB,EAAE,MAAM,CAAC;IACvC,OAAc,WAAW,EAAE,MAAM,CAAC;IAClC,OAAc,WAAW,EAAE,MAAM,CAAC;IAClC,OAAc,SAAS,EAAE,gBAAgB,CAAC;IAC1C,WAAkB,OAAO,qBAAqC;IAC9D,WAAkB,GAAG,iBAAiC;IACtD,WAAkB,QAAQ,oBAA6B;IAEvD,gBAAgB;IAChB,WAAkB,aAAa,iCAA6E;IAE5G,OAAO;IAEP;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAmB/B,OAAO,CAAC,MAAM,CAAC,WAAW;IAqD1B,qDAAqD;IACrD,WAAkB,UAAU,8BAA+B;IAE3D,0FAA0F;WAC5E,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;IAK9F,wFAAwF;WAC1E,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIhF;;;OAGG;WACiB,cAAc,CAAC,aAAa,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC5F,WAAkB,OAAO,YAAsC;IAE/D;;;;;;OAMG;WACiB,OAAO,CAAC,IAAI,CAAC,EAAE,gBAAgB;CAmCpD"}
1
+ {"version":3,"file":"ElectronHost.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronHost.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAC;AAI1E,OAAO,EAAE,UAAU,EAAuB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAA8D,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAwB1I;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2IAA2I;IAC3I,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,aAAa,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACzC,wDAAwD;IACxD,WAAW,CAAC,EAAE,CAAC,OAAO,UAAU,CAAC,EAAE,CAAC;CACrC;AAED,YAAY;AACZ,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAED,YAAY;AACZ,MAAM,WAAW,yBAA0B,SAAQ,+BAA+B;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,CAAC,SAAS,GAAG,QAAQ,GAAG,aAAa,GAAG,sBAAsB,CAAC,CAAC;CACjF;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAc;IACjC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAU;IAC3C,OAAO,CAAC,MAAM,CAAC,SAAS,CAAkB;IAC1C,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA0B;IAC1D,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAgB;IAC3C,OAAc,gBAAgB,EAAE,MAAM,CAAC;IACvC,OAAc,WAAW,EAAE,MAAM,CAAC;IAClC,OAAc,WAAW,EAAE,MAAM,CAAC;IAClC,OAAc,SAAS,EAAE,gBAAgB,CAAC;IAC1C,WAAkB,OAAO,qBAAqC;IAC9D,WAAkB,GAAG,iBAAiC;IACtD,WAAkB,QAAQ,oBAA6B;IAEvD,OAAO;IAEP;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAmB/B,OAAO,CAAC,MAAM,CAAC,WAAW;IAqD1B,qDAAqD;IACrD,WAAkB,UAAU,8BAA+B;IAE3D,0FAA0F;WAC5E,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;IAK9F,wFAAwF;WAC1E,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIhF;;;OAGG;WACiB,cAAc,CAAC,aAAa,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC5F,WAAkB,OAAO,YAAsC;IAE/D;;;;;;OAMG;WACiB,OAAO,CAAC,IAAI,CAAC,EAAE,gBAAgB;CA4BpD"}
@@ -11,7 +11,6 @@ const core_bentley_1 = require("@itwin/core-bentley");
11
11
  const core_backend_1 = require("@itwin/core-backend");
12
12
  const core_common_1 = require("@itwin/core-common");
13
13
  const ElectronRpcManager_1 = require("../common/ElectronRpcManager");
14
- const ElectronAuthorizationBackend_1 = require("./ElectronAuthorizationBackend");
15
14
  // cSpell:ignore signin devserver webcontents copyfile unmaximize eopt
16
15
  class ElectronIpc {
17
16
  addListener(channel, listener) {
@@ -41,8 +40,6 @@ class ElectronHost {
41
40
  static get ipcMain() { return this._electron.ipcMain; }
42
41
  static get app() { return this._electron.app; }
43
42
  static get electron() { return this._electron; }
44
- /** @internal */
45
- static get authorization() { return core_backend_1.IModelHost.authorizationClient; }
46
43
  /**
47
44
  * Converts an "electron://frontend/" URL to an absolute file path.
48
45
  *
@@ -173,7 +170,7 @@ class ElectronHost {
173
170
  * @note This method must only be called from the backend of an Electron app (i.e. when [ProcessDetector.isElectronAppBackend]($bentley) is `true`).
174
171
  */
175
172
  static async startup(opts) {
176
- var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o;
173
+ var _a, _b, _c, _d, _f, _g, _h, _j;
177
174
  if (!core_bentley_1.ProcessDetector.isElectronAppBackend)
178
175
  throw new Error("Not running under Electron");
179
176
  if (!this.isValid) {
@@ -198,11 +195,6 @@ class ElectronHost {
198
195
  ElectronAppHandler.register();
199
196
  (_j = (_h = opts.electronHost) === null || _h === void 0 ? void 0 : _h.ipcHandlers) === null || _j === void 0 ? void 0 : _j.forEach((ipc) => ipc.register());
200
197
  }
201
- const authorizationBackend = new ElectronAuthorizationBackend_1.ElectronAuthorizationBackend((_k = opts.electronHost) === null || _k === void 0 ? void 0 : _k.authConfig);
202
- const connectivityStatus = core_backend_1.NativeHost.checkInternetConnectivity();
203
- if (((_l = opts.electronHost) === null || _l === void 0 ? void 0 : _l.authConfig) && true !== ((_m = opts.electronHost) === null || _m === void 0 ? void 0 : _m.noInitializeAuthClient) && connectivityStatus === core_common_1.InternetConnectivityStatus.Online)
204
- await authorizationBackend.initialize((_o = opts.electronHost) === null || _o === void 0 ? void 0 : _o.authConfig);
205
- core_backend_1.IModelHost.authorizationClient = authorizationBackend;
206
198
  }
207
199
  }
208
200
  exports.ElectronHost = ElectronHost;
@@ -1 +1 @@
1
- {"version":3,"file":"ElectronHost.js","sourceRoot":"","sources":["../../../src/backend/ElectronHost.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\n// Note: only import types! Does not create a `require(\"electron\")` in JavaScript after transpiling. That's important so this file can\r\n// be imported by apps that sometimes use Electron and sometimes not. Call to `ElectronBackend.initialize`\r\n// will do the necessary `require(\"electron\")`\r\n// IMPORTANT: Do not call or construct any of these imports. Otherwise, a require(\"electron\") call will be emitted at top level.\r\n// Instead, use `ElectronHost.electron.<type>`\r\nimport { BrowserWindow, BrowserWindowConstructorOptions } from \"electron\";\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport { BeDuration, IModelStatus, ProcessDetector } from \"@itwin/core-bentley\";\r\nimport { IModelHost, IpcHandler, IpcHost, NativeHost, NativeHostOpts } from \"@itwin/core-backend\";\r\nimport { IModelError, InternetConnectivityStatus, IpcListener, IpcSocketBackend, NativeAppAuthorizationConfiguration, RemoveFunction, RpcConfiguration, RpcInterfaceDefinition } from \"@itwin/core-common\";\r\nimport { ElectronRpcConfiguration, ElectronRpcManager } from \"../common/ElectronRpcManager\";\r\nimport { ElectronAuthorizationBackend } from \"./ElectronAuthorizationBackend\";\r\n\r\n// cSpell:ignore signin devserver webcontents copyfile unmaximize eopt\r\n\r\nclass ElectronIpc implements IpcSocketBackend {\r\n public addListener(channel: string, listener: IpcListener): RemoveFunction {\r\n ElectronHost.ipcMain.addListener(channel, listener);\r\n return () => ElectronHost.ipcMain.removeListener(channel, listener);\r\n }\r\n public removeListener(channel: string, listener: IpcListener) {\r\n ElectronHost.ipcMain.removeListener(channel, listener);\r\n }\r\n public send(channel: string, ...args: any[]): void {\r\n const window = ElectronHost.mainWindow ?? ElectronHost.electron.BrowserWindow.getAllWindows()[0];\r\n window?.webContents.send(channel, ...args);\r\n }\r\n public handle(channel: string, listener: (evt: any, ...args: any[]) => Promise<any>): RemoveFunction {\r\n ElectronHost.ipcMain.removeHandler(channel); // make sure there's not already a handler registered\r\n ElectronHost.ipcMain.handle(channel, listener);\r\n return () => ElectronHost.ipcMain.removeHandler(channel);\r\n }\r\n}\r\n\r\n/**\r\n * Options for [[ElectronHost.startup]]\r\n * @beta\r\n */\r\nexport interface ElectronHostOptions {\r\n /** the path to find web resources */\r\n webResourcesPath?: string;\r\n /** filename for the app's icon, relative to [[webResourcesPath]] */\r\n iconName?: string;\r\n /** name of frontend url to open. */\r\n frontendURL?: string;\r\n /** use a development server rather than the \"electron\" protocol for loading frontend (see https://www.electronjs.org/docs/api/protocol) */\r\n developmentServer?: boolean;\r\n /** port number for development server. Default is 3000 */\r\n frontendPort?: number;\r\n /** list of RPC interface definitions to register */\r\n rpcInterfaces?: RpcInterfaceDefinition[];\r\n /** list of [IpcHandler]($common) classes to register */\r\n ipcHandlers?: (typeof IpcHandler)[];\r\n /** if present, [[NativeHost.authorizationClient]] will be set to an instance of NativeAppAuthorizationBackend and will be initialized. */\r\n authConfig?: NativeAppAuthorizationConfiguration;\r\n /** if true, do not attempt to initialize AuthorizationClient on startup */\r\n noInitializeAuthClient?: boolean;\r\n applicationName?: never; // this should be supplied in NativeHostOpts\r\n}\r\n\r\n/** @beta */\r\nexport interface ElectronHostOpts extends NativeHostOpts {\r\n electronHost?: ElectronHostOptions;\r\n}\r\n\r\n/** @beta */\r\nexport interface ElectronHostWindowOptions extends BrowserWindowConstructorOptions {\r\n storeWindowName?: string;\r\n /** The style of window title bar. Default is `default`. */\r\n titleBarStyle?: (\"default\" | \"hidden\" | \"hiddenInset\" | \"customButtonsOnHover\");\r\n}\r\n\r\n/** the size and position of a window as stored in the settings file.\r\n * @beta\r\n */\r\nexport interface WindowSizeAndPositionProps {\r\n width: number;\r\n height: number;\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/**\r\n * The backend for Electron-based desktop applications\r\n * @beta\r\n */\r\nexport class ElectronHost {\r\n private static _ipc: ElectronIpc;\r\n private static _developmentServer: boolean;\r\n private static _electron: typeof Electron;\r\n private static _electronFrontend = \"electron://frontend/\";\r\n private static _mainWindow?: BrowserWindow;\r\n public static webResourcesPath: string;\r\n public static appIconPath: string;\r\n public static frontendURL: string;\r\n public static rpcConfig: RpcConfiguration;\r\n public static get ipcMain() { return this._electron.ipcMain; }\r\n public static get app() { return this._electron.app; }\r\n public static get electron() { return this._electron; }\r\n\r\n /** @internal */\r\n public static get authorization() { return IModelHost.authorizationClient as ElectronAuthorizationBackend; }\r\n\r\n private constructor() { }\r\n\r\n /**\r\n * Converts an \"electron://frontend/\" URL to an absolute file path.\r\n *\r\n * We use this protocol in production builds because our frontend must be built with absolute URLs,\r\n * however, since we're loading everything directly from the install directory, we cannot know the\r\n * absolute path at build time.\r\n */\r\n private static parseElectronUrl(requestedUrl: string): string {\r\n // Note that the \"frontend/\" path is arbitrary - this is just so we can handle *some* relative URLs...\r\n let assetPath = requestedUrl.substr(this._electronFrontend.length);\r\n if (assetPath.length === 0)\r\n assetPath = \"index.html\";\r\n assetPath = path.normalize(`${this.webResourcesPath}/${assetPath}`);\r\n // File protocols don't follow symlinks, so we need to resolve this to a real path.\r\n // However, if the file doesn't exist, it's fine to return an invalid path here - the request will just fail with net::ERR_FILE_NOT_FOUND\r\n try {\r\n assetPath = fs.realpathSync(assetPath);\r\n } catch (error) {\r\n // eslint-disable-next-line no-console\r\n // console.warn(`WARNING: Frontend requested \"${requestedUrl}\", but ${assetPath} does not exist`);\r\n }\r\n if (!assetPath.startsWith(this.webResourcesPath))\r\n throw new Error(`Access to files outside installation directory (${this.webResourcesPath}) is prohibited`);\r\n return assetPath;\r\n }\r\n\r\n private static _openWindow(options?: ElectronHostWindowOptions) {\r\n const opts: BrowserWindowConstructorOptions = {\r\n ...options,\r\n autoHideMenuBar: true,\r\n icon: this.appIconPath,\r\n webPreferences: {\r\n ...options?.webPreferences,\r\n\r\n // These web preference variables should not be overriden by the ElectronHostWindowOptions\r\n preload: require.resolve(/* webpack: copyfile */\"./ElectronPreload.js\"),\r\n experimentalFeatures: false,\r\n nodeIntegration: false,\r\n contextIsolation: true,\r\n sandbox: true,\r\n nativeWindowOpen: true,\r\n nodeIntegrationInWorker: false,\r\n nodeIntegrationInSubFrames: false,\r\n },\r\n };\r\n\r\n this._mainWindow = new (this.electron.BrowserWindow)(opts);\r\n ElectronRpcConfiguration.targetWindowId = this._mainWindow.id;\r\n this._mainWindow.on(\"closed\", () => this._mainWindow = undefined);\r\n this._mainWindow.loadURL(this.frontendURL); // eslint-disable-line @typescript-eslint/no-floating-promises\r\n\r\n /** Monitors and saves main window size, position and maximized state */\r\n if (options?.storeWindowName) {\r\n const mainWindow = this._mainWindow;\r\n const name = options.storeWindowName;\r\n const saveWindowPosition = () => {\r\n const resolution = mainWindow.getSize();\r\n const position = mainWindow.getPosition();\r\n const pos: WindowSizeAndPositionProps = {\r\n width: resolution[0],\r\n height: resolution[1],\r\n x: position[0],\r\n y: position[1],\r\n };\r\n NativeHost.settingsStore.setData(`windowPos-${name}`, JSON.stringify(pos));\r\n };\r\n const saveMaximized = (maximized: boolean) => {\r\n if (!maximized)\r\n saveWindowPosition();\r\n NativeHost.settingsStore.setData(`windowMaximized-${name}`, maximized);\r\n };\r\n\r\n mainWindow.on(\"resized\", () => saveWindowPosition());\r\n mainWindow.on(\"moved\", () => saveWindowPosition());\r\n mainWindow.on(\"maximize\", () => saveMaximized(true));\r\n mainWindow.on(\"unmaximize\", () => saveMaximized(false));\r\n }\r\n }\r\n\r\n /** The \"main\" BrowserWindow for this application. */\r\n public static get mainWindow() { return this._mainWindow; }\r\n\r\n /** Gets window size and position for a window, by name, from settings file, if present */\r\n public static getWindowSizeSetting(windowName: string): WindowSizeAndPositionProps | undefined {\r\n const saved = NativeHost.settingsStore.getString(`windowPos-${windowName}`);\r\n return saved ? JSON.parse(saved) as WindowSizeAndPositionProps : undefined;\r\n }\r\n\r\n /** Gets \"window maximized\" flag for a window, by name, from settings file if present */\r\n public static getWindowMaximizedSetting(windowName: string): boolean | undefined {\r\n return NativeHost.settingsStore.getBoolean(`windowMaximized-${windowName}`);\r\n }\r\n\r\n /**\r\n * Open the main Window when the app is ready.\r\n * @param windowOptions Options for constructing the main BrowserWindow. See: https://electronjs.org/docs/api/browser-window#new-browserwindowoptions\r\n */\r\n public static async openMainWindow(windowOptions?: ElectronHostWindowOptions): Promise<void> {\r\n const app = this.app;\r\n // quit the application when all windows are closed (unless we're running on MacOS)\r\n app.on(\"window-all-closed\", () => {\r\n if (process.platform !== \"darwin\")\r\n app.quit();\r\n });\r\n\r\n // re-open the main window if it was closed and the app is re-activated (this is the normal MacOS behavior)\r\n app.on(\"activate\", () => {\r\n if (!this._mainWindow)\r\n this._openWindow(windowOptions);\r\n });\r\n\r\n if (this._developmentServer) {\r\n // Occasionally, the electron backend may start before the webpack devserver has even started.\r\n // If this happens, we'll just retry and keep reloading the page.\r\n app.on(\"web-contents-created\", (_e, webcontents) => {\r\n webcontents.on(\"did-fail-load\", async (_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {\r\n // errorCode -102 is CONNECTION_REFUSED - see https://cs.chromium.org/chromium/src/net/base/net_error_list.h\r\n if (isMainFrame && errorCode === -102) {\r\n await BeDuration.wait(100);\r\n webcontents.reload();\r\n }\r\n });\r\n });\r\n }\r\n\r\n await app.whenReady();\r\n\r\n if (!this._developmentServer) {\r\n // handle any \"electron://\" requests and redirect them to \"file://\" URLs\r\n this.electron.protocol.registerFileProtocol(\"electron\", (request, callback) => callback(this.parseElectronUrl(request.url))); // eslint-disable-line @typescript-eslint/no-var-requires\r\n }\r\n\r\n this._openWindow(windowOptions);\r\n }\r\n\r\n public static get isValid() { return this._ipc !== undefined; }\r\n\r\n /**\r\n * Initialize the backend of an Electron app.\r\n * This method configures the backend for all of the inter-process communication (RPC and IPC) for an\r\n * Electron app. It should be called from your Electron main function.\r\n * @param opts Options that control aspects of your backend.\r\n * @note This method must only be called from the backend of an Electron app (i.e. when [ProcessDetector.isElectronAppBackend]($bentley) is `true`).\r\n */\r\n public static async startup(opts?: ElectronHostOpts) {\r\n if (!ProcessDetector.isElectronAppBackend)\r\n throw new Error(\"Not running under Electron\");\r\n\r\n if (!this.isValid) {\r\n this._electron = require(\"electron\");\r\n this._ipc = new ElectronIpc();\r\n const app = this.app;\r\n if (!app.isReady())\r\n this.electron.protocol.registerSchemesAsPrivileged([{ scheme: \"electron\", privileges: { standard: true, secure: true } }]);\r\n const eopt = opts?.electronHost;\r\n this._developmentServer = eopt?.developmentServer ?? false;\r\n const frontendPort = eopt?.frontendPort ?? 3000;\r\n this.webResourcesPath = eopt?.webResourcesPath ?? \"\";\r\n this.frontendURL = eopt?.frontendURL ?? (this._developmentServer ? `http://localhost:${frontendPort}` : `${this._electronFrontend}index.html`);\r\n this.appIconPath = path.join(this.webResourcesPath, eopt?.iconName ?? \"appicon.ico\");\r\n this.rpcConfig = ElectronRpcManager.initializeBackend(this._ipc, eopt?.rpcInterfaces);\r\n }\r\n\r\n opts = opts ?? {};\r\n opts.ipcHost = opts.ipcHost ?? {};\r\n opts.ipcHost.socket = this._ipc;\r\n await NativeHost.startup(opts);\r\n if (IpcHost.isValid) {\r\n ElectronAppHandler.register();\r\n opts.electronHost?.ipcHandlers?.forEach((ipc) => ipc.register());\r\n }\r\n\r\n const authorizationBackend = new ElectronAuthorizationBackend(opts.electronHost?.authConfig);\r\n const connectivityStatus = NativeHost.checkInternetConnectivity();\r\n if (opts.electronHost?.authConfig && true !== opts.electronHost?.noInitializeAuthClient && connectivityStatus === InternetConnectivityStatus.Online)\r\n await authorizationBackend.initialize(opts.electronHost?.authConfig);\r\n\r\n IModelHost.authorizationClient = authorizationBackend;\r\n }\r\n}\r\n\r\nclass ElectronAppHandler extends IpcHandler {\r\n public get channelName() { return \"electron-safe\"; }\r\n public async callElectron(member: string, method: string, ...args: any) {\r\n const electronMember = (ElectronHost.electron as any)[member];\r\n const func = electronMember[method];\r\n if (typeof func !== \"function\")\r\n throw new IModelError(IModelStatus.FunctionNotFound, `Method ${method} not found electron.${member}`);\r\n\r\n return func.call(electronMember, ...args);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"ElectronHost.js","sourceRoot":"","sources":["../../../src/backend/ElectronHost.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\n// Note: only import types! Does not create a `require(\"electron\")` in JavaScript after transpiling. That's important so this file can\r\n// be imported by apps that sometimes use Electron and sometimes not. Call to `ElectronBackend.initialize`\r\n// will do the necessary `require(\"electron\")`\r\n// IMPORTANT: Do not call or construct any of these imports. Otherwise, a require(\"electron\") call will be emitted at top level.\r\n// Instead, use `ElectronHost.electron.<type>`\r\n\r\nimport { BrowserWindow, BrowserWindowConstructorOptions } from \"electron\";\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport { BeDuration, IModelStatus, ProcessDetector } from \"@itwin/core-bentley\";\r\nimport { IpcHandler, IpcHost, NativeHost, NativeHostOpts } from \"@itwin/core-backend\";\r\nimport { IModelError, IpcListener, IpcSocketBackend, RemoveFunction, RpcConfiguration, RpcInterfaceDefinition } from \"@itwin/core-common\";\r\nimport { ElectronRpcConfiguration, ElectronRpcManager } from \"../common/ElectronRpcManager\";\r\n\r\n// cSpell:ignore signin devserver webcontents copyfile unmaximize eopt\r\n\r\nclass ElectronIpc implements IpcSocketBackend {\r\n public addListener(channel: string, listener: IpcListener): RemoveFunction {\r\n ElectronHost.ipcMain.addListener(channel, listener);\r\n return () => ElectronHost.ipcMain.removeListener(channel, listener);\r\n }\r\n public removeListener(channel: string, listener: IpcListener) {\r\n ElectronHost.ipcMain.removeListener(channel, listener);\r\n }\r\n public send(channel: string, ...args: any[]): void {\r\n const window = ElectronHost.mainWindow ?? ElectronHost.electron.BrowserWindow.getAllWindows()[0];\r\n window?.webContents.send(channel, ...args);\r\n }\r\n public handle(channel: string, listener: (evt: any, ...args: any[]) => Promise<any>): RemoveFunction {\r\n ElectronHost.ipcMain.removeHandler(channel); // make sure there's not already a handler registered\r\n ElectronHost.ipcMain.handle(channel, listener);\r\n return () => ElectronHost.ipcMain.removeHandler(channel);\r\n }\r\n}\r\n\r\n/**\r\n * Options for [[ElectronHost.startup]]\r\n * @beta\r\n */\r\nexport interface ElectronHostOptions {\r\n /** the path to find web resources */\r\n webResourcesPath?: string;\r\n /** filename for the app's icon, relative to [[webResourcesPath]] */\r\n iconName?: string;\r\n /** name of frontend url to open. */\r\n frontendURL?: string;\r\n /** use a development server rather than the \"electron\" protocol for loading frontend (see https://www.electronjs.org/docs/api/protocol) */\r\n developmentServer?: boolean;\r\n /** port number for development server. Default is 3000 */\r\n frontendPort?: number;\r\n /** list of RPC interface definitions to register */\r\n rpcInterfaces?: RpcInterfaceDefinition[];\r\n /** list of [IpcHandler]($common) classes to register */\r\n ipcHandlers?: (typeof IpcHandler)[];\r\n}\r\n\r\n/** @beta */\r\nexport interface ElectronHostOpts extends NativeHostOpts {\r\n electronHost?: ElectronHostOptions;\r\n}\r\n\r\n/** @beta */\r\nexport interface ElectronHostWindowOptions extends BrowserWindowConstructorOptions {\r\n storeWindowName?: string;\r\n /** The style of window title bar. Default is `default`. */\r\n titleBarStyle?: (\"default\" | \"hidden\" | \"hiddenInset\" | \"customButtonsOnHover\");\r\n}\r\n\r\n/** the size and position of a window as stored in the settings file.\r\n * @beta\r\n */\r\nexport interface WindowSizeAndPositionProps {\r\n width: number;\r\n height: number;\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/**\r\n * The backend for Electron-based desktop applications\r\n * @beta\r\n */\r\nexport class ElectronHost {\r\n private static _ipc: ElectronIpc;\r\n private static _developmentServer: boolean;\r\n private static _electron: typeof Electron;\r\n private static _electronFrontend = \"electron://frontend/\";\r\n private static _mainWindow?: BrowserWindow;\r\n public static webResourcesPath: string;\r\n public static appIconPath: string;\r\n public static frontendURL: string;\r\n public static rpcConfig: RpcConfiguration;\r\n public static get ipcMain() { return this._electron.ipcMain; }\r\n public static get app() { return this._electron.app; }\r\n public static get electron() { return this._electron; }\r\n\r\n private constructor() { }\r\n\r\n /**\r\n * Converts an \"electron://frontend/\" URL to an absolute file path.\r\n *\r\n * We use this protocol in production builds because our frontend must be built with absolute URLs,\r\n * however, since we're loading everything directly from the install directory, we cannot know the\r\n * absolute path at build time.\r\n */\r\n private static parseElectronUrl(requestedUrl: string): string {\r\n // Note that the \"frontend/\" path is arbitrary - this is just so we can handle *some* relative URLs...\r\n let assetPath = requestedUrl.substr(this._electronFrontend.length);\r\n if (assetPath.length === 0)\r\n assetPath = \"index.html\";\r\n assetPath = path.normalize(`${this.webResourcesPath}/${assetPath}`);\r\n // File protocols don't follow symlinks, so we need to resolve this to a real path.\r\n // However, if the file doesn't exist, it's fine to return an invalid path here - the request will just fail with net::ERR_FILE_NOT_FOUND\r\n try {\r\n assetPath = fs.realpathSync(assetPath);\r\n } catch (error) {\r\n // eslint-disable-next-line no-console\r\n // console.warn(`WARNING: Frontend requested \"${requestedUrl}\", but ${assetPath} does not exist`);\r\n }\r\n if (!assetPath.startsWith(this.webResourcesPath))\r\n throw new Error(`Access to files outside installation directory (${this.webResourcesPath}) is prohibited`);\r\n return assetPath;\r\n }\r\n\r\n private static _openWindow(options?: ElectronHostWindowOptions) {\r\n const opts: BrowserWindowConstructorOptions = {\r\n ...options,\r\n autoHideMenuBar: true,\r\n icon: this.appIconPath,\r\n webPreferences: {\r\n ...options?.webPreferences,\r\n\r\n // These web preference variables should not be overriden by the ElectronHostWindowOptions\r\n preload: require.resolve(/* webpack: copyfile */\"./ElectronPreload.js\"),\r\n experimentalFeatures: false,\r\n nodeIntegration: false,\r\n contextIsolation: true,\r\n sandbox: true,\r\n nativeWindowOpen: true,\r\n nodeIntegrationInWorker: false,\r\n nodeIntegrationInSubFrames: false,\r\n },\r\n };\r\n\r\n this._mainWindow = new (this.electron.BrowserWindow)(opts);\r\n ElectronRpcConfiguration.targetWindowId = this._mainWindow.id;\r\n this._mainWindow.on(\"closed\", () => this._mainWindow = undefined);\r\n this._mainWindow.loadURL(this.frontendURL); // eslint-disable-line @typescript-eslint/no-floating-promises\r\n\r\n /** Monitors and saves main window size, position and maximized state */\r\n if (options?.storeWindowName) {\r\n const mainWindow = this._mainWindow;\r\n const name = options.storeWindowName;\r\n const saveWindowPosition = () => {\r\n const resolution = mainWindow.getSize();\r\n const position = mainWindow.getPosition();\r\n const pos: WindowSizeAndPositionProps = {\r\n width: resolution[0],\r\n height: resolution[1],\r\n x: position[0],\r\n y: position[1],\r\n };\r\n NativeHost.settingsStore.setData(`windowPos-${name}`, JSON.stringify(pos));\r\n };\r\n const saveMaximized = (maximized: boolean) => {\r\n if (!maximized)\r\n saveWindowPosition();\r\n NativeHost.settingsStore.setData(`windowMaximized-${name}`, maximized);\r\n };\r\n\r\n mainWindow.on(\"resized\", () => saveWindowPosition());\r\n mainWindow.on(\"moved\", () => saveWindowPosition());\r\n mainWindow.on(\"maximize\", () => saveMaximized(true));\r\n mainWindow.on(\"unmaximize\", () => saveMaximized(false));\r\n }\r\n }\r\n\r\n /** The \"main\" BrowserWindow for this application. */\r\n public static get mainWindow() { return this._mainWindow; }\r\n\r\n /** Gets window size and position for a window, by name, from settings file, if present */\r\n public static getWindowSizeSetting(windowName: string): WindowSizeAndPositionProps | undefined {\r\n const saved = NativeHost.settingsStore.getString(`windowPos-${windowName}`);\r\n return saved ? JSON.parse(saved) as WindowSizeAndPositionProps : undefined;\r\n }\r\n\r\n /** Gets \"window maximized\" flag for a window, by name, from settings file if present */\r\n public static getWindowMaximizedSetting(windowName: string): boolean | undefined {\r\n return NativeHost.settingsStore.getBoolean(`windowMaximized-${windowName}`);\r\n }\r\n\r\n /**\r\n * Open the main Window when the app is ready.\r\n * @param windowOptions Options for constructing the main BrowserWindow. See: https://electronjs.org/docs/api/browser-window#new-browserwindowoptions\r\n */\r\n public static async openMainWindow(windowOptions?: ElectronHostWindowOptions): Promise<void> {\r\n const app = this.app;\r\n // quit the application when all windows are closed (unless we're running on MacOS)\r\n app.on(\"window-all-closed\", () => {\r\n if (process.platform !== \"darwin\")\r\n app.quit();\r\n });\r\n\r\n // re-open the main window if it was closed and the app is re-activated (this is the normal MacOS behavior)\r\n app.on(\"activate\", () => {\r\n if (!this._mainWindow)\r\n this._openWindow(windowOptions);\r\n });\r\n\r\n if (this._developmentServer) {\r\n // Occasionally, the electron backend may start before the webpack devserver has even started.\r\n // If this happens, we'll just retry and keep reloading the page.\r\n app.on(\"web-contents-created\", (_e, webcontents) => {\r\n webcontents.on(\"did-fail-load\", async (_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {\r\n // errorCode -102 is CONNECTION_REFUSED - see https://cs.chromium.org/chromium/src/net/base/net_error_list.h\r\n if (isMainFrame && errorCode === -102) {\r\n await BeDuration.wait(100);\r\n webcontents.reload();\r\n }\r\n });\r\n });\r\n }\r\n\r\n await app.whenReady();\r\n\r\n if (!this._developmentServer) {\r\n // handle any \"electron://\" requests and redirect them to \"file://\" URLs\r\n this.electron.protocol.registerFileProtocol(\"electron\", (request, callback) => callback(this.parseElectronUrl(request.url))); // eslint-disable-line @typescript-eslint/no-var-requires\r\n }\r\n\r\n this._openWindow(windowOptions);\r\n }\r\n\r\n public static get isValid() { return this._ipc !== undefined; }\r\n\r\n /**\r\n * Initialize the backend of an Electron app.\r\n * This method configures the backend for all of the inter-process communication (RPC and IPC) for an\r\n * Electron app. It should be called from your Electron main function.\r\n * @param opts Options that control aspects of your backend.\r\n * @note This method must only be called from the backend of an Electron app (i.e. when [ProcessDetector.isElectronAppBackend]($bentley) is `true`).\r\n */\r\n public static async startup(opts?: ElectronHostOpts) {\r\n if (!ProcessDetector.isElectronAppBackend)\r\n throw new Error(\"Not running under Electron\");\r\n\r\n if (!this.isValid) {\r\n this._electron = require(\"electron\");\r\n this._ipc = new ElectronIpc();\r\n const app = this.app;\r\n if (!app.isReady())\r\n this.electron.protocol.registerSchemesAsPrivileged([{ scheme: \"electron\", privileges: { standard: true, secure: true } }]);\r\n const eopt = opts?.electronHost;\r\n this._developmentServer = eopt?.developmentServer ?? false;\r\n const frontendPort = eopt?.frontendPort ?? 3000;\r\n this.webResourcesPath = eopt?.webResourcesPath ?? \"\";\r\n this.frontendURL = eopt?.frontendURL ?? (this._developmentServer ? `http://localhost:${frontendPort}` : `${this._electronFrontend}index.html`);\r\n this.appIconPath = path.join(this.webResourcesPath, eopt?.iconName ?? \"appicon.ico\");\r\n this.rpcConfig = ElectronRpcManager.initializeBackend(this._ipc, eopt?.rpcInterfaces);\r\n }\r\n\r\n opts = opts ?? {};\r\n opts.ipcHost = opts.ipcHost ?? {};\r\n opts.ipcHost.socket = this._ipc;\r\n await NativeHost.startup(opts);\r\n if (IpcHost.isValid) {\r\n ElectronAppHandler.register();\r\n opts.electronHost?.ipcHandlers?.forEach((ipc) => ipc.register());\r\n }\r\n }\r\n}\r\n\r\nclass ElectronAppHandler extends IpcHandler {\r\n public get channelName() { return \"electron-safe\"; }\r\n public async callElectron(member: string, method: string, ...args: any) {\r\n const electronMember = (ElectronHost.electron as any)[member];\r\n const func = electronMember[method];\r\n if (typeof func !== \"function\")\r\n throw new IModelError(IModelStatus.FunctionNotFound, `Method ${method} not found electron.${member}`);\r\n\r\n return func.call(electronMember, ...args);\r\n }\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/core-electron",
3
- "version": "3.0.0-extension.1",
3
+ "version": "3.1.0-dev.6",
4
4
  "description": "iTwin.js ElectronHost and ElectronApp",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -20,23 +20,21 @@
20
20
  "url": "http://www.bentley.com"
21
21
  },
22
22
  "peerDependencies": {
23
- "@itwin/core-bentley": "^3.0.0-extension.1",
24
- "@itwin/core-backend": "^3.0.0-extension.1",
25
- "@itwin/core-common": "^3.0.0-extension.1",
26
- "@itwin/core-frontend": "^3.0.0-extension.1",
27
- "@bentley/itwin-client": "^3.0.0-extension.1",
28
- "@itwin/presentation-common": "^3.0.0-extension.1",
23
+ "@itwin/core-backend": "^3.1.0-dev.6",
24
+ "@itwin/core-bentley": "^3.1.0-dev.6",
25
+ "@itwin/core-common": "^3.1.0-dev.6",
26
+ "@itwin/core-frontend": "^3.1.0-dev.6",
27
+ "@itwin/presentation-common": "^3.1.0-dev.6",
29
28
  "electron": "^14.0.0"
30
29
  },
31
30
  "devDependencies": {
32
- "@itwin/core-bentley": "3.0.0-extension.1",
33
- "@itwin/build-tools": "3.0.0-extension.1",
34
- "@itwin/eslint-plugin": "3.0.0-extension.1",
35
- "@itwin/core-backend": "3.0.0-extension.1",
36
- "@itwin/core-common": "3.0.0-extension.1",
37
- "@itwin/core-frontend": "3.0.0-extension.1",
38
- "@bentley/itwin-client": "3.0.0-extension.1",
39
- "@itwin/presentation-common": "3.0.0-extension.1",
31
+ "@itwin/build-tools": "3.1.0-dev.6",
32
+ "@itwin/core-backend": "3.1.0-dev.6",
33
+ "@itwin/core-bentley": "3.1.0-dev.6",
34
+ "@itwin/core-common": "3.1.0-dev.6",
35
+ "@itwin/core-frontend": "3.1.0-dev.6",
36
+ "@itwin/eslint-plugin": "3.1.0-dev.6",
37
+ "@itwin/presentation-common": "3.1.0-dev.6",
40
38
  "@types/node": "14.14.31",
41
39
  "electron": "^14.0.0",
42
40
  "eslint": "^7.11.0",
@@ -64,5 +62,6 @@
64
62
  "lint": "eslint -f visualstudio \"./src/**/*.ts\" 1>&2",
65
63
  "test": "",
66
64
  "cover": ""
67
- }
65
+ },
66
+ "readme": "# @itwin/core-electron\r\n\r\nCopyright © Bentley Systems, Incorporated. All rights reserved. See LICENSE.md for license terms and full copyright notice.\r\n\r\n## Description\r\n\r\nThe __@itwin/core-electron__ package contains the electron utilities to write an iTwin.js application based on Electron.\r\n\r\n## Documentation\r\n\r\nSee the [iTwin.js](https://www.itwinjs.org) documentation for more information.\r\n"
68
67
  }
@@ -1,71 +0,0 @@
1
- /** @packageDocumentation
2
- * @module Authentication
3
- */
4
- import { AccessToken } from "@itwin/core-bentley";
5
- import { NativeAppAuthorizationBackend } from "@itwin/core-backend";
6
- import { NativeAppAuthorizationConfiguration } from "@itwin/core-common";
7
- import { ElectronTokenStore } from "./ElectronTokenStore";
8
- /**
9
- * Utility to generate OIDC/OAuth tokens for Desktop Applications
10
- * @beta
11
- */
12
- export declare class ElectronAuthorizationBackend extends NativeAppAuthorizationBackend {
13
- static defaultRedirectUri: string;
14
- private _configuration;
15
- private _tokenResponse;
16
- private _tokenStore?;
17
- private _expiresAt?;
18
- get tokenStore(): ElectronTokenStore;
19
- constructor(config?: NativeAppAuthorizationConfiguration);
20
- get redirectUri(): string;
21
- /**
22
- * Used to initialize the client - must be awaited before any other methods are called.
23
- * The call attempts a silent sign-if possible.
24
- */
25
- initialize(config?: NativeAppAuthorizationConfiguration): Promise<void>;
26
- refreshToken(): Promise<AccessToken>;
27
- /** Loads the access token from the store, and refreshes it if necessary and possible
28
- * @return AccessToken if it's possible to get a valid access token, and undefined otherwise.
29
- */
30
- private loadAccessToken;
31
- /**
32
- * Sign-in completely.
33
- * This is a wrapper around [[signIn]] - the only difference is that the promise resolves
34
- * with the access token after sign in is complete and successful.
35
- */
36
- signInComplete(): Promise<AccessToken>;
37
- /**
38
- * Start the sign-in process
39
- * - calls the onAccessTokenChanged() call back after the authorization completes
40
- * or if there is an error.
41
- * - will attempt in order:
42
- * (i) load any existing authorized user from storage,
43
- * (ii) an interactive signin that requires user input.
44
- */
45
- signIn(): Promise<void>;
46
- private _onAuthorizationResponse;
47
- /**
48
- * Start the sign-out process
49
- * - calls the onAccessTokenChanged() call back after the authorization completes
50
- * or if there is an error.
51
- * - redirects application to the postSignoutRedirectUri specified in the configuration when the sign out is
52
- * complete
53
- */
54
- signOut(): Promise<void>;
55
- /**
56
- * Sign out completely
57
- * This is a wrapper around [[signOut]] - the only difference is that the promise resolves
58
- * after the sign out is complete.
59
- */
60
- signOutComplete(): Promise<void>;
61
- private clearTokenResponse;
62
- private setTokenResponse;
63
- private get _hasExpired();
64
- getAccessToken(): Promise<AccessToken>;
65
- private refreshAccessToken;
66
- /** Swap the authorization code for a refresh token and access token */
67
- private swapAuthorizationCodeForTokens;
68
- private makeRefreshAccessTokenRequest;
69
- private makeRevokeTokenRequest;
70
- }
71
- //# sourceMappingURL=ElectronAuthorizationBackend.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronAuthorizationBackend.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationBackend.ts"],"names":[],"mappings":"AAMA;;GAEG;AAKH,OAAO,EAAE,WAAW,EAA4C,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,6BAA6B,EAAc,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AASzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK1D;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,6BAA6B;IAC7E,OAAc,kBAAkB,SAA2C;IAC3E,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,WAAW,CAAC,CAAqB;IACzC,OAAO,CAAC,UAAU,CAAC,CAAO;IAC1B,IAAW,UAAU,uBAAgC;gBAElC,MAAM,CAAC,EAAE,mCAAmC;IAI/D,IAAW,WAAW,WAA0F;IAEhH;;;OAGG;IACmB,UAAU,CAAC,MAAM,CAAC,EAAE,mCAAmC,GAAG,OAAO,CAAC,IAAI,CAAC;IAchF,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAQjD;;OAEG;YACW,eAAe;IAW7B;;;;OAIG;IACU,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAanD;;;;;;;OAOG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;YAqDtB,wBAAwB;IAsBtC;;;;;;OAMG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;OAIG;IACU,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAa/B,kBAAkB;YAMlB,gBAAgB;IAY9B,OAAO,KAAK,WAAW,GAKtB;IAEqB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;YAM9C,kBAAkB;IAMhC,uEAAuE;YACzD,8BAA8B;YAqB9B,6BAA6B;YAkB7B,sBAAsB;CAqBrC"}
@@ -1,265 +0,0 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- // Code based on the blog article @ https://authguidance.com
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ElectronAuthorizationBackend = void 0;
9
- /** @packageDocumentation
10
- * @module Authentication
11
- */
12
- // cSpell:ignore openid appauth signin Pkce Signout
13
- /* eslint-disable @typescript-eslint/naming-convention */
14
- const core_bentley_1 = require("@itwin/core-bentley");
15
- const core_backend_1 = require("@itwin/core-backend");
16
- const appauth_1 = require("@openid/appauth");
17
- const node_support_1 = require("@openid/appauth/built/node_support");
18
- const ElectronAuthorizationEvents_1 = require("./ElectronAuthorizationEvents");
19
- const ElectronAuthorizationRequestHandler_1 = require("./ElectronAuthorizationRequestHandler");
20
- const ElectronTokenStore_1 = require("./ElectronTokenStore");
21
- const LoopbackWebServer_1 = require("./LoopbackWebServer");
22
- const loggerCategory = "electron-auth";
23
- /**
24
- * Utility to generate OIDC/OAuth tokens for Desktop Applications
25
- * @beta
26
- */
27
- class ElectronAuthorizationBackend extends core_backend_1.NativeAppAuthorizationBackend {
28
- constructor(config) {
29
- super(config);
30
- }
31
- get tokenStore() { return this._tokenStore; }
32
- get redirectUri() { var _a, _b; return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.redirectUri) !== null && _b !== void 0 ? _b : ElectronAuthorizationBackend.defaultRedirectUri; }
33
- /**
34
- * Used to initialize the client - must be awaited before any other methods are called.
35
- * The call attempts a silent sign-if possible.
36
- */
37
- async initialize(config) {
38
- await super.initialize(config);
39
- (0, core_bentley_1.assert)(this.config !== undefined && this.issuerUrl !== undefined, "URL of authorization provider was not initialized");
40
- this._tokenStore = new ElectronTokenStore_1.ElectronTokenStore(this.config.clientId);
41
- const tokenRequestor = new node_support_1.NodeRequestor(); // the Node.js based HTTP client
42
- this._configuration = await appauth_1.AuthorizationServiceConfiguration.fetchFromIssuer(this.issuerUrl, tokenRequestor);
43
- core_bentley_1.Logger.logTrace(loggerCategory, "Initialized service configuration", () => ({ configuration: this._configuration }));
44
- // Attempt to load the access token from store
45
- await this.loadAccessToken();
46
- }
47
- async refreshToken() {
48
- if (this._tokenResponse === undefined || this._tokenResponse.refreshToken === undefined)
49
- return "";
50
- const token = `Bearer ${this._tokenResponse.refreshToken}`;
51
- return this.refreshAccessToken(token);
52
- }
53
- /** Loads the access token from the store, and refreshes it if necessary and possible
54
- * @return AccessToken if it's possible to get a valid access token, and undefined otherwise.
55
- */
56
- async loadAccessToken() {
57
- const tokenResponse = await this.tokenStore.load();
58
- if (tokenResponse === undefined || tokenResponse.refreshToken === undefined)
59
- return "";
60
- try {
61
- return await this.refreshAccessToken(tokenResponse.refreshToken);
62
- }
63
- catch (err) {
64
- return "";
65
- }
66
- }
67
- /**
68
- * Sign-in completely.
69
- * This is a wrapper around [[signIn]] - the only difference is that the promise resolves
70
- * with the access token after sign in is complete and successful.
71
- */
72
- async signInComplete() {
73
- return new Promise((resolve, reject) => {
74
- core_backend_1.NativeHost.onAccessTokenChanged.addOnce((token) => {
75
- if (token !== "") {
76
- resolve(token);
77
- }
78
- else {
79
- reject(new Error("Failed to sign in"));
80
- }
81
- });
82
- this.signIn().catch((err) => reject(err));
83
- });
84
- }
85
- /**
86
- * Start the sign-in process
87
- * - calls the onAccessTokenChanged() call back after the authorization completes
88
- * or if there is an error.
89
- * - will attempt in order:
90
- * (i) load any existing authorized user from storage,
91
- * (ii) an interactive signin that requires user input.
92
- */
93
- async signIn() {
94
- if (!this._configuration)
95
- throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Not initialized. First call initialize()");
96
- (0, core_bentley_1.assert)(this.config !== undefined);
97
- // Attempt to load the access token from store
98
- const token = await this.loadAccessToken();
99
- if (token)
100
- return this.setAccessToken(token);
101
- // Create the authorization request
102
- const nativeConfig = this.config;
103
- const authReqJson = {
104
- client_id: nativeConfig.clientId,
105
- redirect_uri: this.redirectUri,
106
- scope: nativeConfig.scope,
107
- response_type: appauth_1.AuthorizationRequest.RESPONSE_TYPE_CODE,
108
- extras: { prompt: "consent", access_type: "offline" },
109
- };
110
- const authorizationRequest = new appauth_1.AuthorizationRequest(authReqJson, new node_support_1.NodeCrypto(), true /* = usePkce */);
111
- await authorizationRequest.setupCodeVerifier();
112
- // Create events for this signin attempt
113
- const authorizationEvents = new ElectronAuthorizationEvents_1.ElectronAuthorizationEvents();
114
- // Ensure that completion callbacks are correlated to the correct authorization request
115
- LoopbackWebServer_1.LoopbackWebServer.addCorrelationState(authorizationRequest.state, authorizationEvents);
116
- // Start a web server to listen to the browser requests
117
- LoopbackWebServer_1.LoopbackWebServer.start(nativeConfig);
118
- const authorizationHandler = new ElectronAuthorizationRequestHandler_1.ElectronAuthorizationRequestHandler(authorizationEvents);
119
- // Setup a notifier to obtain the result of authorization
120
- const notifier = new appauth_1.AuthorizationNotifier();
121
- authorizationHandler.setAuthorizationNotifier(notifier);
122
- notifier.setAuthorizationListener(async (authRequest, authResponse, authError) => {
123
- core_bentley_1.Logger.logTrace(loggerCategory, "Authorization listener invoked", () => ({ authRequest, authResponse, authError }));
124
- const tokenResponse = await this._onAuthorizationResponse(authRequest, authResponse, authError);
125
- authorizationEvents.onAuthorizationResponseCompleted.raiseEvent(authError ? authError : undefined);
126
- if (!tokenResponse)
127
- await this.clearTokenResponse();
128
- else
129
- await this.setTokenResponse(tokenResponse);
130
- });
131
- // Start the signin
132
- await authorizationHandler.performAuthorizationRequest(this._configuration, authorizationRequest);
133
- }
134
- async _onAuthorizationResponse(authRequest, authResponse, authError) {
135
- // Phase 1 of login has completed to fetch the authorization code - check for errors
136
- if (authError) {
137
- core_bentley_1.Logger.logError(loggerCategory, "Authorization error. Unable to get authorization code.", () => authError);
138
- return undefined;
139
- }
140
- if (!authResponse || authResponse.state !== authRequest.state) {
141
- core_bentley_1.Logger.logError(loggerCategory, "Authorization error. Unable to get authorization code", () => ({
142
- error: "invalid_state",
143
- errorDescription: "The login response state did not match the login request state.",
144
- }));
145
- return undefined;
146
- }
147
- // Phase 2: Swap the authorization code for the access token
148
- const tokenResponse = await this.swapAuthorizationCodeForTokens(authResponse.code, authRequest.internal.code_verifier);
149
- core_bentley_1.Logger.logTrace(loggerCategory, "Authorization completed, and issued access token");
150
- return tokenResponse;
151
- }
152
- /**
153
- * Start the sign-out process
154
- * - calls the onAccessTokenChanged() call back after the authorization completes
155
- * or if there is an error.
156
- * - redirects application to the postSignoutRedirectUri specified in the configuration when the sign out is
157
- * complete
158
- */
159
- async signOut() {
160
- await this.makeRevokeTokenRequest();
161
- }
162
- /**
163
- * Sign out completely
164
- * This is a wrapper around [[signOut]] - the only difference is that the promise resolves
165
- * after the sign out is complete.
166
- */
167
- async signOutComplete() {
168
- return new Promise((resolve, reject) => {
169
- core_backend_1.NativeHost.onAccessTokenChanged.addOnce((token) => {
170
- if (token === "") {
171
- resolve();
172
- }
173
- else {
174
- reject(new Error("Failed to sign out"));
175
- }
176
- });
177
- this.signOut().catch((err) => reject(err));
178
- });
179
- }
180
- async clearTokenResponse() {
181
- this._tokenResponse = undefined;
182
- await this.tokenStore.delete();
183
- this.setAccessToken("");
184
- }
185
- async setTokenResponse(tokenResponse) {
186
- var _a;
187
- const accessToken = tokenResponse.accessToken;
188
- this._tokenResponse = tokenResponse;
189
- const expiresAtMilliseconds = (tokenResponse.issuedAt + ((_a = tokenResponse.expiresIn) !== null && _a !== void 0 ? _a : 0)) * 1000;
190
- this._expiresAt = new Date(expiresAtMilliseconds);
191
- await this.tokenStore.save(this._tokenResponse);
192
- const bearerToken = `${tokenResponse.tokenType} ${accessToken}`;
193
- this.setAccessToken(bearerToken);
194
- return bearerToken;
195
- }
196
- get _hasExpired() {
197
- if (!this._expiresAt)
198
- return false;
199
- return this._expiresAt.getTime() - Date.now() <= 1 * 60 * 1000; // Consider 1 minute before expiry as expired
200
- }
201
- async getAccessToken() {
202
- if (this._hasExpired || !this._accessToken)
203
- this.setAccessToken(await this.refreshToken());
204
- return this._accessToken;
205
- }
206
- async refreshAccessToken(refreshToken) {
207
- const tokenResponse = await this.makeRefreshAccessTokenRequest(refreshToken);
208
- core_bentley_1.Logger.logTrace(loggerCategory, "Refresh token completed, and issued access token");
209
- return this.setTokenResponse(tokenResponse);
210
- }
211
- /** Swap the authorization code for a refresh token and access token */
212
- async swapAuthorizationCodeForTokens(authCode, codeVerifier) {
213
- if (!this._configuration)
214
- throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Not initialized. First call initialize()");
215
- (0, core_bentley_1.assert)(this.config !== undefined);
216
- const nativeConfig = this.config;
217
- const extras = { code_verifier: codeVerifier };
218
- const tokenRequestJson = {
219
- grant_type: appauth_1.GRANT_TYPE_AUTHORIZATION_CODE,
220
- code: authCode,
221
- redirect_uri: this.redirectUri,
222
- client_id: nativeConfig.clientId,
223
- extras,
224
- };
225
- const tokenRequest = new appauth_1.TokenRequest(tokenRequestJson);
226
- const tokenRequestor = new node_support_1.NodeRequestor();
227
- const tokenHandler = new appauth_1.BaseTokenRequestHandler(tokenRequestor);
228
- return tokenHandler.performTokenRequest(this._configuration, tokenRequest);
229
- }
230
- async makeRefreshAccessTokenRequest(refreshToken) {
231
- if (!this._configuration)
232
- throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Not initialized. First call initialize()");
233
- (0, core_bentley_1.assert)(this.config !== undefined);
234
- const tokenRequestJson = {
235
- grant_type: appauth_1.GRANT_TYPE_REFRESH_TOKEN,
236
- refresh_token: refreshToken,
237
- redirect_uri: this.redirectUri,
238
- client_id: this.config.clientId,
239
- };
240
- const tokenRequest = new appauth_1.TokenRequest(tokenRequestJson);
241
- const tokenRequestor = new node_support_1.NodeRequestor();
242
- const tokenHandler = new appauth_1.BaseTokenRequestHandler(tokenRequestor);
243
- return tokenHandler.performTokenRequest(this._configuration, tokenRequest);
244
- }
245
- async makeRevokeTokenRequest() {
246
- if (!this._tokenResponse)
247
- throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Missing refresh token. First call signIn() and ensure it's successful");
248
- (0, core_bentley_1.assert)(this.config !== undefined);
249
- const refreshToken = this._tokenResponse.refreshToken;
250
- const revokeTokenRequestJson = {
251
- token: refreshToken,
252
- token_type_hint: "refresh_token",
253
- client_id: this.config.clientId,
254
- };
255
- const revokeTokenRequest = new appauth_1.RevokeTokenRequest(revokeTokenRequestJson);
256
- const tokenRequestor = new node_support_1.NodeRequestor();
257
- const tokenHandler = new appauth_1.BaseTokenRequestHandler(tokenRequestor);
258
- await tokenHandler.performRevokeTokenRequest(this._configuration, revokeTokenRequest);
259
- core_bentley_1.Logger.logTrace(loggerCategory, "Authorization revoked, and removed access token");
260
- await this.clearTokenResponse();
261
- }
262
- }
263
- exports.ElectronAuthorizationBackend = ElectronAuthorizationBackend;
264
- ElectronAuthorizationBackend.defaultRedirectUri = "http://localhost:3000/signin-callback";
265
- //# sourceMappingURL=ElectronAuthorizationBackend.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronAuthorizationBackend.js","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationBackend.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\n// cSpell:ignore openid appauth signin Pkce Signout\r\n/* eslint-disable @typescript-eslint/naming-convention */\r\n\r\nimport { AccessToken, assert, AuthStatus, BentleyError, Logger } from \"@itwin/core-bentley\";\r\nimport { NativeAppAuthorizationBackend, NativeHost } from \"@itwin/core-backend\";\r\nimport { NativeAppAuthorizationConfiguration } from \"@itwin/core-common\";\r\nimport {\r\n AuthorizationError, AuthorizationNotifier, AuthorizationRequest, AuthorizationRequestJson, AuthorizationResponse, AuthorizationServiceConfiguration,\r\n BaseTokenRequestHandler, GRANT_TYPE_AUTHORIZATION_CODE, GRANT_TYPE_REFRESH_TOKEN, RevokeTokenRequest, RevokeTokenRequestJson, StringMap,\r\n TokenRequest, TokenRequestHandler, TokenRequestJson, TokenResponse,\r\n} from \"@openid/appauth\";\r\nimport { NodeCrypto, NodeRequestor } from \"@openid/appauth/built/node_support\";\r\nimport { ElectronAuthorizationEvents } from \"./ElectronAuthorizationEvents\";\r\nimport { ElectronAuthorizationRequestHandler } from \"./ElectronAuthorizationRequestHandler\";\r\nimport { ElectronTokenStore } from \"./ElectronTokenStore\";\r\nimport { LoopbackWebServer } from \"./LoopbackWebServer\";\r\n\r\nconst loggerCategory = \"electron-auth\";\r\n\r\n/**\r\n * Utility to generate OIDC/OAuth tokens for Desktop Applications\r\n * @beta\r\n */\r\nexport class ElectronAuthorizationBackend extends NativeAppAuthorizationBackend {\r\n public static defaultRedirectUri = \"http://localhost:3000/signin-callback\";\r\n private _configuration: AuthorizationServiceConfiguration | undefined;\r\n private _tokenResponse: TokenResponse | undefined;\r\n private _tokenStore?: ElectronTokenStore;\r\n private _expiresAt?: Date;\r\n public get tokenStore() { return this._tokenStore!; }\r\n\r\n public constructor(config?: NativeAppAuthorizationConfiguration) {\r\n super(config);\r\n }\r\n\r\n public get redirectUri() { return this.config?.redirectUri ?? ElectronAuthorizationBackend.defaultRedirectUri; }\r\n\r\n /**\r\n * Used to initialize the client - must be awaited before any other methods are called.\r\n * The call attempts a silent sign-if possible.\r\n */\r\n public override async initialize(config?: NativeAppAuthorizationConfiguration): Promise<void> {\r\n await super.initialize(config);\r\n assert(this.config !== undefined && this.issuerUrl !== undefined, \"URL of authorization provider was not initialized\");\r\n\r\n this._tokenStore = new ElectronTokenStore(this.config.clientId);\r\n\r\n const tokenRequestor = new NodeRequestor(); // the Node.js based HTTP client\r\n this._configuration = await AuthorizationServiceConfiguration.fetchFromIssuer(this.issuerUrl, tokenRequestor);\r\n Logger.logTrace(loggerCategory, \"Initialized service configuration\", () => ({ configuration: this._configuration }));\r\n\r\n // Attempt to load the access token from store\r\n await this.loadAccessToken();\r\n }\r\n\r\n public async refreshToken(): Promise<AccessToken> {\r\n if (this._tokenResponse === undefined || this._tokenResponse.refreshToken === undefined)\r\n return \"\";\r\n\r\n const token = `Bearer ${this._tokenResponse.refreshToken}`;\r\n return this.refreshAccessToken(token);\r\n }\r\n\r\n /** Loads the access token from the store, and refreshes it if necessary and possible\r\n * @return AccessToken if it's possible to get a valid access token, and undefined otherwise.\r\n */\r\n private async loadAccessToken(): Promise<AccessToken> {\r\n const tokenResponse = await this.tokenStore.load();\r\n if (tokenResponse === undefined || tokenResponse.refreshToken === undefined)\r\n return \"\";\r\n try {\r\n return await this.refreshAccessToken(tokenResponse.refreshToken);\r\n } catch (err) {\r\n return \"\";\r\n }\r\n }\r\n\r\n /**\r\n * Sign-in completely.\r\n * This is a wrapper around [[signIn]] - the only difference is that the promise resolves\r\n * with the access token after sign in is complete and successful.\r\n */\r\n public async signInComplete(): Promise<AccessToken> {\r\n return new Promise<AccessToken>((resolve, reject) => {\r\n NativeHost.onAccessTokenChanged.addOnce((token) => {\r\n if (token !== \"\") {\r\n resolve(token);\r\n } else {\r\n reject(new Error(\"Failed to sign in\"));\r\n }\r\n });\r\n this.signIn().catch((err) => reject(err));\r\n });\r\n }\r\n\r\n /**\r\n * Start the sign-in process\r\n * - calls the onAccessTokenChanged() call back after the authorization completes\r\n * or if there is an error.\r\n * - will attempt in order:\r\n * (i) load any existing authorized user from storage,\r\n * (ii) an interactive signin that requires user input.\r\n */\r\n public async signIn(): Promise<void> {\r\n if (!this._configuration)\r\n throw new BentleyError(AuthStatus.Error, \"Not initialized. First call initialize()\");\r\n assert(this.config !== undefined);\r\n\r\n // Attempt to load the access token from store\r\n const token = await this.loadAccessToken();\r\n if (token)\r\n return this.setAccessToken(token);\r\n\r\n // Create the authorization request\r\n const nativeConfig = this.config;\r\n const authReqJson: AuthorizationRequestJson = {\r\n client_id: nativeConfig.clientId,\r\n redirect_uri: this.redirectUri,\r\n scope: nativeConfig.scope,\r\n response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,\r\n extras: { prompt: \"consent\", access_type: \"offline\" },\r\n };\r\n const authorizationRequest = new AuthorizationRequest(authReqJson, new NodeCrypto(), true /* = usePkce */);\r\n await authorizationRequest.setupCodeVerifier();\r\n\r\n // Create events for this signin attempt\r\n const authorizationEvents = new ElectronAuthorizationEvents();\r\n\r\n // Ensure that completion callbacks are correlated to the correct authorization request\r\n LoopbackWebServer.addCorrelationState(authorizationRequest.state, authorizationEvents);\r\n\r\n // Start a web server to listen to the browser requests\r\n LoopbackWebServer.start(nativeConfig);\r\n\r\n const authorizationHandler = new ElectronAuthorizationRequestHandler(authorizationEvents);\r\n\r\n // Setup a notifier to obtain the result of authorization\r\n const notifier = new AuthorizationNotifier();\r\n authorizationHandler.setAuthorizationNotifier(notifier);\r\n notifier.setAuthorizationListener(async (authRequest: AuthorizationRequest, authResponse: AuthorizationResponse | null, authError: AuthorizationError | null) => {\r\n Logger.logTrace(loggerCategory, \"Authorization listener invoked\", () => ({ authRequest, authResponse, authError }));\r\n\r\n const tokenResponse = await this._onAuthorizationResponse(authRequest, authResponse, authError);\r\n\r\n authorizationEvents.onAuthorizationResponseCompleted.raiseEvent(authError ? authError : undefined);\r\n\r\n if (!tokenResponse)\r\n await this.clearTokenResponse();\r\n else\r\n await this.setTokenResponse(tokenResponse);\r\n });\r\n\r\n // Start the signin\r\n await authorizationHandler.performAuthorizationRequest(this._configuration, authorizationRequest);\r\n }\r\n\r\n private async _onAuthorizationResponse(authRequest: AuthorizationRequest, authResponse: AuthorizationResponse | null, authError: AuthorizationError | null): Promise<TokenResponse | undefined> {\r\n\r\n // Phase 1 of login has completed to fetch the authorization code - check for errors\r\n if (authError) {\r\n Logger.logError(loggerCategory, \"Authorization error. Unable to get authorization code.\", () => authError);\r\n return undefined;\r\n }\r\n\r\n if (!authResponse || authResponse.state !== authRequest.state) {\r\n Logger.logError(loggerCategory, \"Authorization error. Unable to get authorization code\", () => ({\r\n error: \"invalid_state\",\r\n errorDescription: \"The login response state did not match the login request state.\",\r\n }));\r\n return undefined;\r\n }\r\n\r\n // Phase 2: Swap the authorization code for the access token\r\n const tokenResponse = await this.swapAuthorizationCodeForTokens(authResponse.code, authRequest.internal!.code_verifier);\r\n Logger.logTrace(loggerCategory, \"Authorization completed, and issued access token\");\r\n return tokenResponse;\r\n }\r\n\r\n /**\r\n * Start the sign-out process\r\n * - calls the onAccessTokenChanged() call back after the authorization completes\r\n * or if there is an error.\r\n * - redirects application to the postSignoutRedirectUri specified in the configuration when the sign out is\r\n * complete\r\n */\r\n public async signOut(): Promise<void> {\r\n await this.makeRevokeTokenRequest();\r\n }\r\n\r\n /**\r\n * Sign out completely\r\n * This is a wrapper around [[signOut]] - the only difference is that the promise resolves\r\n * after the sign out is complete.\r\n */\r\n public async signOutComplete(): Promise<void> {\r\n return new Promise<void>((resolve, reject) => {\r\n NativeHost.onAccessTokenChanged.addOnce((token) => {\r\n if (token === \"\") {\r\n resolve();\r\n } else {\r\n reject(new Error(\"Failed to sign out\"));\r\n }\r\n });\r\n this.signOut().catch((err) => reject(err));\r\n });\r\n }\r\n\r\n private async clearTokenResponse() {\r\n this._tokenResponse = undefined;\r\n await this.tokenStore.delete();\r\n this.setAccessToken(\"\");\r\n }\r\n\r\n private async setTokenResponse(tokenResponse: TokenResponse): Promise<AccessToken> {\r\n const accessToken = tokenResponse.accessToken;\r\n this._tokenResponse = tokenResponse;\r\n const expiresAtMilliseconds = (tokenResponse.issuedAt + (tokenResponse.expiresIn ?? 0)) * 1000;\r\n this._expiresAt = new Date(expiresAtMilliseconds);\r\n\r\n await this.tokenStore.save(this._tokenResponse);\r\n const bearerToken = `${tokenResponse.tokenType} ${accessToken}`;\r\n this.setAccessToken(bearerToken);\r\n return bearerToken;\r\n }\r\n\r\n private get _hasExpired(): boolean {\r\n if (!this._expiresAt)\r\n return false;\r\n\r\n return this._expiresAt.getTime() - Date.now() <= 1 * 60 * 1000; // Consider 1 minute before expiry as expired\r\n }\r\n\r\n public override async getAccessToken(): Promise<AccessToken> {\r\n if (this._hasExpired || !this._accessToken)\r\n this.setAccessToken(await this.refreshToken());\r\n return this._accessToken;\r\n }\r\n\r\n private async refreshAccessToken(refreshToken: string): Promise<AccessToken> {\r\n const tokenResponse = await this.makeRefreshAccessTokenRequest(refreshToken);\r\n Logger.logTrace(loggerCategory, \"Refresh token completed, and issued access token\");\r\n return this.setTokenResponse(tokenResponse);\r\n }\r\n\r\n /** Swap the authorization code for a refresh token and access token */\r\n private async swapAuthorizationCodeForTokens(authCode: string, codeVerifier: string): Promise<TokenResponse> {\r\n if (!this._configuration)\r\n throw new BentleyError(AuthStatus.Error, \"Not initialized. First call initialize()\");\r\n assert(this.config !== undefined);\r\n\r\n const nativeConfig = this.config;\r\n const extras: StringMap = { code_verifier: codeVerifier };\r\n const tokenRequestJson: TokenRequestJson = {\r\n grant_type: GRANT_TYPE_AUTHORIZATION_CODE,\r\n code: authCode,\r\n redirect_uri: this.redirectUri,\r\n client_id: nativeConfig.clientId,\r\n extras,\r\n };\r\n\r\n const tokenRequest = new TokenRequest(tokenRequestJson);\r\n const tokenRequestor = new NodeRequestor();\r\n const tokenHandler: TokenRequestHandler = new BaseTokenRequestHandler(tokenRequestor);\r\n return tokenHandler.performTokenRequest(this._configuration, tokenRequest);\r\n }\r\n\r\n private async makeRefreshAccessTokenRequest(refreshToken: string): Promise<TokenResponse> {\r\n if (!this._configuration)\r\n throw new BentleyError(AuthStatus.Error, \"Not initialized. First call initialize()\");\r\n assert(this.config !== undefined);\r\n\r\n const tokenRequestJson: TokenRequestJson = {\r\n grant_type: GRANT_TYPE_REFRESH_TOKEN,\r\n refresh_token: refreshToken,\r\n redirect_uri: this.redirectUri,\r\n client_id: this.config.clientId,\r\n };\r\n\r\n const tokenRequest = new TokenRequest(tokenRequestJson);\r\n const tokenRequestor = new NodeRequestor();\r\n const tokenHandler: TokenRequestHandler = new BaseTokenRequestHandler(tokenRequestor);\r\n return tokenHandler.performTokenRequest(this._configuration, tokenRequest);\r\n }\r\n\r\n private async makeRevokeTokenRequest(): Promise<void> {\r\n if (!this._tokenResponse)\r\n throw new BentleyError(AuthStatus.Error, \"Missing refresh token. First call signIn() and ensure it's successful\");\r\n assert(this.config !== undefined);\r\n\r\n const refreshToken = this._tokenResponse.refreshToken!;\r\n\r\n const revokeTokenRequestJson: RevokeTokenRequestJson = {\r\n token: refreshToken,\r\n token_type_hint: \"refresh_token\",\r\n client_id: this.config.clientId,\r\n };\r\n\r\n const revokeTokenRequest = new RevokeTokenRequest(revokeTokenRequestJson);\r\n const tokenRequestor = new NodeRequestor();\r\n const tokenHandler: TokenRequestHandler = new BaseTokenRequestHandler(tokenRequestor);\r\n await tokenHandler.performRevokeTokenRequest(this._configuration!, revokeTokenRequest);\r\n\r\n Logger.logTrace(loggerCategory, \"Authorization revoked, and removed access token\");\r\n await this.clearTokenResponse();\r\n }\r\n}\r\n"]}
@@ -1,20 +0,0 @@
1
- /** @packageDocumentation
2
- * @module Authentication
3
- */
4
- import { BeEvent } from "@itwin/core-bentley";
5
- import { AuthorizationErrorJson, AuthorizationResponseJson } from "@openid/appauth";
6
- /** @internal */
7
- export declare type AuthorizationResponseCompletedListener = (error?: AuthorizationErrorJson) => void;
8
- /** @internal */
9
- export declare type AuthorizationResponseListener = (error: AuthorizationErrorJson | null, response: AuthorizationResponseJson | null) => void;
10
- /**
11
- * Internal events used by authorization by DesktopAuthorizationClient and related classes
12
- * @internal
13
- */
14
- export declare class ElectronAuthorizationEvents {
15
- /** Event raised when the authorization is completed */
16
- readonly onAuthorizationResponseCompleted: BeEvent<AuthorizationResponseCompletedListener>;
17
- /** Event raised when a response is received from the authorization server with the authorization code */
18
- readonly onAuthorizationResponse: BeEvent<AuthorizationResponseListener>;
19
- }
20
- //# sourceMappingURL=ElectronAuthorizationEvents.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronAuthorizationEvents.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationEvents.ts"],"names":[],"mappings":"AAMA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,gBAAgB;AAChB,oBAAY,sCAAsC,GAAG,CAAC,KAAK,CAAC,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAE9F,gBAAgB;AAChB,oBAAY,6BAA6B,GAAG,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,EAAE,QAAQ,EAAE,yBAAyB,GAAG,IAAI,KAAK,IAAI,CAAC;AAEvI;;;GAGG;AACH,qBAAa,2BAA2B;IACtC,uDAAuD;IACvD,SAAgB,gCAAgC,kDAAyD;IAEzG,yGAAyG;IACzG,SAAgB,uBAAuB,yCAAgD;CACxF"}
@@ -1,26 +0,0 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- // Code based on the blog article @ https://authguidance.com
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ElectronAuthorizationEvents = void 0;
9
- /** @packageDocumentation
10
- * @module Authentication
11
- */
12
- const core_bentley_1 = require("@itwin/core-bentley");
13
- /**
14
- * Internal events used by authorization by DesktopAuthorizationClient and related classes
15
- * @internal
16
- */
17
- class ElectronAuthorizationEvents {
18
- constructor() {
19
- /** Event raised when the authorization is completed */
20
- this.onAuthorizationResponseCompleted = new core_bentley_1.BeEvent();
21
- /** Event raised when a response is received from the authorization server with the authorization code */
22
- this.onAuthorizationResponse = new core_bentley_1.BeEvent();
23
- }
24
- }
25
- exports.ElectronAuthorizationEvents = ElectronAuthorizationEvents;
26
- //# sourceMappingURL=ElectronAuthorizationEvents.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronAuthorizationEvents.js","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationEvents.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,4DAA4D;;;AAE5D;;GAEG;AAEH,sDAA8C;AAS9C;;;GAGG;AACH,MAAa,2BAA2B;IAAxC;QACE,uDAAuD;QACvC,qCAAgC,GAAG,IAAI,sBAAO,EAA0C,CAAC;QAEzG,yGAAyG;QACzF,4BAAuB,GAAG,IAAI,sBAAO,EAAiC,CAAC;IACzF,CAAC;CAAA;AAND,kEAMC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport { BeEvent } from \"@itwin/core-bentley\";\r\nimport { AuthorizationErrorJson, AuthorizationResponseJson } from \"@openid/appauth\";\r\n\r\n/** @internal */\r\nexport type AuthorizationResponseCompletedListener = (error?: AuthorizationErrorJson) => void;\r\n\r\n/** @internal */\r\nexport type AuthorizationResponseListener = (error: AuthorizationErrorJson | null, response: AuthorizationResponseJson | null) => void;\r\n\r\n/**\r\n * Internal events used by authorization by DesktopAuthorizationClient and related classes\r\n * @internal\r\n */\r\nexport class ElectronAuthorizationEvents {\r\n /** Event raised when the authorization is completed */\r\n public readonly onAuthorizationResponseCompleted = new BeEvent<AuthorizationResponseCompletedListener>();\r\n\r\n /** Event raised when a response is received from the authorization server with the authorization code */\r\n public readonly onAuthorizationResponse = new BeEvent<AuthorizationResponseListener>();\r\n}\r\n"]}
@@ -1,25 +0,0 @@
1
- import { AuthorizationRequest, AuthorizationRequestHandler, AuthorizationRequestResponse, AuthorizationServiceConfiguration } from "@openid/appauth";
2
- import { ElectronAuthorizationEvents } from "./ElectronAuthorizationEvents";
3
- /**
4
- * Utility to setup a local web server that listens to authorization responses to the browser and make the necessary redirections
5
- * @internal
6
- */
7
- export declare class ElectronAuthorizationRequestHandler extends AuthorizationRequestHandler {
8
- private _authorizationPromise;
9
- private _authorizationEvents;
10
- /**
11
- * Constructor
12
- */
13
- constructor(authorizationEvents: ElectronAuthorizationEvents);
14
- /**
15
- * Makes an authorization request on the system browser
16
- */
17
- performAuthorizationRequest(serviceConfiguration: AuthorizationServiceConfiguration, authRequest: AuthorizationRequest): Promise<void>;
18
- /**
19
- * Checks if an authorization flow can be completed, and completes it.
20
- * The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`
21
- * if not ready.
22
- */
23
- protected completeAuthorizationRequest(): Promise<AuthorizationRequestResponse | null>;
24
- }
25
- //# sourceMappingURL=ElectronAuthorizationRequestHandler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronAuthorizationRequestHandler.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationRequestHandler.ts"],"names":[],"mappings":"AAYA,OAAO,EACuC,oBAAoB,EAAE,2BAA2B,EAAE,4BAA4B,EAChG,iCAAiC,EAC7D,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E;;;GAGG;AACH,qBAAa,mCAAoC,SAAQ,2BAA2B;IAClF,OAAO,CAAC,qBAAqB,CAAsD;IACnF,OAAO,CAAC,oBAAoB,CAA8B;IAE1D;;OAEG;gBACgB,mBAAmB,EAAE,2BAA2B;IAKnE;;OAEG;IACU,2BAA2B,CAAC,oBAAoB,EAAE,iCAAiC,EAAE,WAAW,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnJ;;;;OAIG;cACa,4BAA4B,IAAI,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC;CAG7F"}
@@ -1,63 +0,0 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- // Code based on the blog article @ https://authguidance.com
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ElectronAuthorizationRequestHandler = void 0;
9
- /** @packageDocumentation
10
- * @module Authentication
11
- */
12
- const open = require("open");
13
- const core_bentley_1 = require("@itwin/core-bentley");
14
- const appauth_1 = require("@openid/appauth");
15
- const node_support_1 = require("@openid/appauth/built/node_support");
16
- /**
17
- * Utility to setup a local web server that listens to authorization responses to the browser and make the necessary redirections
18
- * @internal
19
- */
20
- class ElectronAuthorizationRequestHandler extends appauth_1.AuthorizationRequestHandler {
21
- /**
22
- * Constructor
23
- */
24
- constructor(authorizationEvents) {
25
- super(new appauth_1.BasicQueryStringUtils(), new node_support_1.NodeCrypto());
26
- this._authorizationPromise = null;
27
- this._authorizationEvents = authorizationEvents;
28
- }
29
- /**
30
- * Makes an authorization request on the system browser
31
- */
32
- async performAuthorizationRequest(serviceConfiguration, authRequest) {
33
- core_bentley_1.Logger.logTrace("electron-auth", "Making authorization request", () => ({ serviceConfiguration, authRequest }));
34
- // Setup a promise to process the authorization response
35
- this._authorizationPromise = new Promise((resolve, _reject) => {
36
- // Wrap the response from the web browser (with the authorization code)
37
- this._authorizationEvents.onAuthorizationResponse.addOnce((authErrorJson, authResponseJson) => {
38
- // Resolve the full response including the request
39
- const authRequestResponse = {
40
- request: authRequest,
41
- error: authErrorJson ? new appauth_1.AuthorizationError(authErrorJson) : null,
42
- response: authResponseJson ? new appauth_1.AuthorizationResponse(authResponseJson) : null,
43
- };
44
- resolve(authRequestResponse);
45
- // Ask the base class to call our completeAuthorizationRequest - this calls the registered notifier to broadcast the event outside of the client
46
- this.completeAuthorizationRequestIfPossible(); // eslint-disable-line @typescript-eslint/no-floating-promises
47
- });
48
- });
49
- // Compose the request and invoke in the browser
50
- const authUrl = this.buildRequestUrl(serviceConfiguration, authRequest);
51
- await open(authUrl);
52
- }
53
- /**
54
- * Checks if an authorization flow can be completed, and completes it.
55
- * The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`
56
- * if not ready.
57
- */
58
- async completeAuthorizationRequest() {
59
- return this._authorizationPromise;
60
- }
61
- }
62
- exports.ElectronAuthorizationRequestHandler = ElectronAuthorizationRequestHandler;
63
- //# sourceMappingURL=ElectronAuthorizationRequestHandler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronAuthorizationRequestHandler.js","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationRequestHandler.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,4DAA4D;;;AAE5D;;GAEG;AAEH,6BAA6B;AAC7B,sDAA6C;AAC7C,6CAGyB;AACzB,qEAAgE;AAGhE;;;GAGG;AACH,MAAa,mCAAoC,SAAQ,qCAA2B;IAIlF;;OAEG;IACH,YAAmB,mBAAgD;QACjE,KAAK,CAAC,IAAI,+BAAqB,EAAE,EAAE,IAAI,yBAAU,EAAE,CAAC,CAAC;QAP/C,0BAAqB,GAAiD,IAAI,CAAC;QAQjF,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;IAClD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,2BAA2B,CAAC,oBAAuD,EAAE,WAAiC;QACjI,qBAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,8BAA8B,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;QAEhH,wDAAwD;QACxD,IAAI,CAAC,qBAAqB,GAAG,IAAI,OAAO,CAA+B,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;YAE1F,uEAAuE;YACvE,IAAI,CAAC,oBAAoB,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,aAA4C,EAAE,gBAAkD,EAAE,EAAE;gBAE7J,kDAAkD;gBAClD,MAAM,mBAAmB,GAAiC;oBACxD,OAAO,EAAE,WAAW;oBACpB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,4BAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI;oBACnE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,+BAAqB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;iBAChF,CAAC;gBACF,OAAO,CAAC,mBAAmB,CAAC,CAAC;gBAE7B,gJAAgJ;gBAChJ,IAAI,CAAC,sCAAsC,EAAE,CAAC,CAAC,8DAA8D;YAC/G,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,gDAAgD;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACxE,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACO,KAAK,CAAC,4BAA4B;QAC1C,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;CACF;AAlDD,kFAkDC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport * as open from \"open\";\r\nimport { Logger } from \"@itwin/core-bentley\";\r\nimport {\r\n AuthorizationError, AuthorizationErrorJson, AuthorizationRequest, AuthorizationRequestHandler, AuthorizationRequestResponse, AuthorizationResponse,\r\n AuthorizationResponseJson, AuthorizationServiceConfiguration, BasicQueryStringUtils,\r\n} from \"@openid/appauth\";\r\nimport { NodeCrypto } from \"@openid/appauth/built/node_support\";\r\nimport { ElectronAuthorizationEvents } from \"./ElectronAuthorizationEvents\";\r\n\r\n/**\r\n * Utility to setup a local web server that listens to authorization responses to the browser and make the necessary redirections\r\n * @internal\r\n */\r\nexport class ElectronAuthorizationRequestHandler extends AuthorizationRequestHandler {\r\n private _authorizationPromise: Promise<AuthorizationRequestResponse> | null = null;\r\n private _authorizationEvents: ElectronAuthorizationEvents;\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor(authorizationEvents: ElectronAuthorizationEvents) {\r\n super(new BasicQueryStringUtils(), new NodeCrypto());\r\n this._authorizationEvents = authorizationEvents;\r\n }\r\n\r\n /**\r\n * Makes an authorization request on the system browser\r\n */\r\n public async performAuthorizationRequest(serviceConfiguration: AuthorizationServiceConfiguration, authRequest: AuthorizationRequest): Promise<void> {\r\n Logger.logTrace(\"electron-auth\", \"Making authorization request\", () => ({ serviceConfiguration, authRequest }));\r\n\r\n // Setup a promise to process the authorization response\r\n this._authorizationPromise = new Promise<AuthorizationRequestResponse>((resolve, _reject) => {\r\n\r\n // Wrap the response from the web browser (with the authorization code)\r\n this._authorizationEvents.onAuthorizationResponse.addOnce((authErrorJson: AuthorizationErrorJson | null, authResponseJson: AuthorizationResponseJson | null) => {\r\n\r\n // Resolve the full response including the request\r\n const authRequestResponse: AuthorizationRequestResponse = {\r\n request: authRequest,\r\n error: authErrorJson ? new AuthorizationError(authErrorJson) : null,\r\n response: authResponseJson ? new AuthorizationResponse(authResponseJson) : null,\r\n };\r\n resolve(authRequestResponse);\r\n\r\n // Ask the base class to call our completeAuthorizationRequest - this calls the registered notifier to broadcast the event outside of the client\r\n this.completeAuthorizationRequestIfPossible(); // eslint-disable-line @typescript-eslint/no-floating-promises\r\n });\r\n });\r\n\r\n // Compose the request and invoke in the browser\r\n const authUrl = this.buildRequestUrl(serviceConfiguration, authRequest);\r\n await open(authUrl);\r\n }\r\n\r\n /**\r\n * Checks if an authorization flow can be completed, and completes it.\r\n * The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`\r\n * if not ready.\r\n */\r\n protected async completeAuthorizationRequest(): Promise<AuthorizationRequestResponse | null> {\r\n return this._authorizationPromise;\r\n }\r\n}\r\n"]}
@@ -1,18 +0,0 @@
1
- import { TokenResponse } from "@openid/appauth";
2
- /**
3
- * Utility to store OIDC AppAuth in secure storage
4
- * @internal
5
- */
6
- export declare class ElectronTokenStore {
7
- private _appStorageKey;
8
- constructor(clientId: string);
9
- private _userName?;
10
- private getUserName;
11
- /** Load token if available */
12
- load(): Promise<TokenResponse | undefined>;
13
- /** Save token after signin */
14
- save(tokenResponse: TokenResponse): Promise<void>;
15
- /** Delete token after signout */
16
- delete(): Promise<void>;
17
- }
18
- //# sourceMappingURL=ElectronTokenStore.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronTokenStore.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronTokenStore.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAqB,MAAM,iBAAiB,CAAC;AAGnE;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,cAAc,CAAS;gBAEZ,QAAQ,EAAE,MAAM;IAInC,OAAO,CAAC,SAAS,CAAC,CAAS;YACb,WAAW;IAMzB,8BAA8B;IACjB,IAAI,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAiBvD,8BAA8B;IACjB,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9D,iCAAiC;IACpB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAUrC"}
@@ -1,66 +0,0 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- // Code based on the blog article @ https://authguidance.com
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ElectronTokenStore = void 0;
9
- /** @packageDocumentation
10
- * @module Authentication
11
- */
12
- const OperatingSystemUserName = require("username");
13
- const appauth_1 = require("@openid/appauth");
14
- const core_backend_1 = require("@itwin/core-backend");
15
- /**
16
- * Utility to store OIDC AppAuth in secure storage
17
- * @internal
18
- */
19
- class ElectronTokenStore {
20
- constructor(clientId) {
21
- this._appStorageKey = `Bentley.iModelJs.OidcTokenStore.${clientId}`;
22
- }
23
- async getUserName() {
24
- if (!this._userName)
25
- this._userName = await OperatingSystemUserName();
26
- return this._userName;
27
- }
28
- /** Load token if available */
29
- async load() {
30
- if (undefined === core_backend_1.IModelHost.platform.KeyTar) // no keytar on Linux yet
31
- return undefined;
32
- const userName = await this.getUserName();
33
- if (!userName)
34
- return;
35
- const tokenResponseStr = await core_backend_1.IModelHost.platform.KeyTar.getPassword(this._appStorageKey, userName);
36
- if (!tokenResponseStr) {
37
- return undefined;
38
- }
39
- const tokenResponseJson = JSON.parse(tokenResponseStr);
40
- return new appauth_1.TokenResponse(tokenResponseJson);
41
- }
42
- /** Save token after signin */
43
- async save(tokenResponse) {
44
- if (undefined === core_backend_1.IModelHost.platform.KeyTar) // no keytar on Linux yet
45
- return;
46
- const userName = await this.getUserName();
47
- if (!userName)
48
- return;
49
- const tokenResponseObj = new appauth_1.TokenResponse(tokenResponse.toJson()); // Workaround for 'stub received bad data' error on windows - see https://github.com/atom/node-keytar/issues/112
50
- tokenResponseObj.accessToken = "";
51
- tokenResponseObj.idToken = "";
52
- const tokenResponseStr = JSON.stringify(tokenResponseObj.toJson());
53
- await core_backend_1.IModelHost.platform.KeyTar.setPassword(this._appStorageKey, userName, tokenResponseStr);
54
- }
55
- /** Delete token after signout */
56
- async delete() {
57
- if (undefined === core_backend_1.IModelHost.platform.KeyTar) // no keytar on Linux yet
58
- return;
59
- const userName = await this.getUserName();
60
- if (!userName)
61
- return;
62
- await core_backend_1.IModelHost.platform.KeyTar.deletePassword(this._appStorageKey, userName);
63
- }
64
- }
65
- exports.ElectronTokenStore = ElectronTokenStore;
66
- //# sourceMappingURL=ElectronTokenStore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ElectronTokenStore.js","sourceRoot":"","sources":["../../../src/backend/ElectronTokenStore.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,4DAA4D;;;AAE5D;;GAEG;AAEH,oDAAoD;AACpD,6CAAmE;AACnE,sDAAiD;AAEjD;;;GAGG;AACH,MAAa,kBAAkB;IAG7B,YAAmB,QAAgB;QACjC,IAAI,CAAC,cAAc,GAAG,mCAAmC,QAAQ,EAAE,CAAC;IACtE,CAAC;IAGO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC,IAAI,CAAC,SAAS;YACjB,IAAI,CAAC,SAAS,GAAG,MAAM,uBAAuB,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,8BAA8B;IACvB,KAAK,CAAC,IAAI;QACf,IAAI,SAAS,KAAK,yBAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;YACrE,OAAO,SAAS,CAAC;QAEnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ;YACX,OAAO;QAET,MAAM,gBAAgB,GAAG,MAAM,yBAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QACrG,IAAI,CAAC,gBAAgB,EAAE;YACrB,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAsB,CAAC;QAC5E,OAAO,IAAI,uBAAa,CAAC,iBAAiB,CAAC,CAAC;IAC9C,CAAC;IAED,8BAA8B;IACvB,KAAK,CAAC,IAAI,CAAC,aAA4B;QAC5C,IAAI,SAAS,KAAK,yBAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;YACrE,OAAO;QAET,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ;YACX,OAAO;QAET,MAAM,gBAAgB,GAAG,IAAI,uBAAa,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,gHAAgH;QACpL,gBAAgB,CAAC,WAAW,GAAG,EAAE,CAAC;QAClC,gBAAgB,CAAC,OAAO,GAAG,EAAE,CAAC;QAE9B,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;QACnE,MAAM,yBAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAChG,CAAC;IAED,iCAAiC;IAC1B,KAAK,CAAC,MAAM;QACjB,IAAI,SAAS,KAAK,yBAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;YACrE,OAAO;QAET,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ;YACX,OAAO;QAET,MAAM,yBAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC;CACF;AA5DD,gDA4DC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport * as OperatingSystemUserName from \"username\";\r\nimport { TokenResponse, TokenResponseJson } from \"@openid/appauth\";\r\nimport { IModelHost } from \"@itwin/core-backend\";\r\n\r\n/**\r\n * Utility to store OIDC AppAuth in secure storage\r\n * @internal\r\n */\r\nexport class ElectronTokenStore {\r\n private _appStorageKey: string;\r\n\r\n public constructor(clientId: string) {\r\n this._appStorageKey = `Bentley.iModelJs.OidcTokenStore.${clientId}`;\r\n }\r\n\r\n private _userName?: string; // Cached user name\r\n private async getUserName(): Promise<string | undefined> {\r\n if (!this._userName)\r\n this._userName = await OperatingSystemUserName();\r\n return this._userName;\r\n }\r\n\r\n /** Load token if available */\r\n public async load(): Promise<TokenResponse | undefined> {\r\n if (undefined === IModelHost.platform.KeyTar) // no keytar on Linux yet\r\n return undefined;\r\n\r\n const userName = await this.getUserName();\r\n if (!userName)\r\n return;\r\n\r\n const tokenResponseStr = await IModelHost.platform.KeyTar.getPassword(this._appStorageKey, userName);\r\n if (!tokenResponseStr) {\r\n return undefined;\r\n }\r\n\r\n const tokenResponseJson = JSON.parse(tokenResponseStr) as TokenResponseJson;\r\n return new TokenResponse(tokenResponseJson);\r\n }\r\n\r\n /** Save token after signin */\r\n public async save(tokenResponse: TokenResponse): Promise<void> {\r\n if (undefined === IModelHost.platform.KeyTar) // no keytar on Linux yet\r\n return;\r\n\r\n const userName = await this.getUserName();\r\n if (!userName)\r\n return;\r\n\r\n const tokenResponseObj = new TokenResponse(tokenResponse.toJson()); // Workaround for 'stub received bad data' error on windows - see https://github.com/atom/node-keytar/issues/112\r\n tokenResponseObj.accessToken = \"\";\r\n tokenResponseObj.idToken = \"\";\r\n\r\n const tokenResponseStr = JSON.stringify(tokenResponseObj.toJson());\r\n await IModelHost.platform.KeyTar.setPassword(this._appStorageKey, userName, tokenResponseStr);\r\n }\r\n\r\n /** Delete token after signout */\r\n public async delete(): Promise<void> {\r\n if (undefined === IModelHost.platform.KeyTar) // no keytar on Linux yet\r\n return;\r\n\r\n const userName = await this.getUserName();\r\n if (!userName)\r\n return;\r\n\r\n await IModelHost.platform.KeyTar.deletePassword(this._appStorageKey, userName);\r\n }\r\n}\r\n"]}
@@ -1,19 +0,0 @@
1
- import { NativeAppAuthorizationConfiguration } from "@itwin/core-common";
2
- import { ElectronAuthorizationEvents } from "./ElectronAuthorizationEvents";
3
- /**
4
- * Web server to listen to authorization requests/responses for the DesktopAuthorizationClient
5
- * @internal
6
- */
7
- export declare class LoopbackWebServer {
8
- private static _httpServer?;
9
- private static _authState;
10
- /** Start a web server to listen to the browser requests */
11
- static start(clientConfiguration: NativeAppAuthorizationConfiguration): void;
12
- /** Add to the authorization state so that the correct response data is used for each request */
13
- static addCorrelationState(state: string, authEvents: ElectronAuthorizationEvents): void;
14
- /** Stop the web server after the authorization was completed */
15
- private static stop;
16
- /** Listen/Handle browser events */
17
- private static onBrowserRequest;
18
- }
19
- //# sourceMappingURL=LoopbackWebServer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LoopbackWebServer.d.ts","sourceRoot":"","sources":["../../../src/backend/LoopbackWebServer.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AA2B5E;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAc;IACzC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAgD;IAEzE,2DAA2D;WAC7C,KAAK,CAAC,mBAAmB,EAAE,mCAAmC;IAS5E,gGAAgG;WAClF,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,2BAA2B,GAAG,IAAI;IAI/F,gEAAgE;IAChE,OAAO,CAAC,MAAM,CAAC,IAAI;IAOnB,mCAAmC;IACnC,OAAO,CAAC,MAAM,CAAC,gBAAgB;CA4ChC"}
@@ -1,101 +0,0 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- // Code based on the blog article @ https://authguidance.com
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.LoopbackWebServer = void 0;
9
- /** @packageDocumentation
10
- * @module Authentication
11
- */
12
- const Http = require("http");
13
- const ElectronAuthorizationBackend_1 = require("./ElectronAuthorizationBackend");
14
- /** Utility to manage re-entrancy if there are multiple login attempts */
15
- class AuthorizationState {
16
- addState(state, authEvents) {
17
- AuthorizationState._stateEventsMap.push([state, authEvents]);
18
- }
19
- removeState(state) {
20
- AuthorizationState._stateEventsMap = AuthorizationState._stateEventsMap.filter((se) => se[0] !== state);
21
- }
22
- // Get events for a received login response
23
- getEvents(state) {
24
- const stateEventsPair = AuthorizationState._stateEventsMap.find((se) => se[0] === state);
25
- if (stateEventsPair) {
26
- return stateEventsPair[1];
27
- }
28
- return null;
29
- }
30
- }
31
- AuthorizationState._stateEventsMap = [];
32
- /**
33
- * Web server to listen to authorization requests/responses for the DesktopAuthorizationClient
34
- * @internal
35
- */
36
- class LoopbackWebServer {
37
- /** Start a web server to listen to the browser requests */
38
- static start(clientConfiguration) {
39
- var _a;
40
- if (LoopbackWebServer._httpServer)
41
- return;
42
- LoopbackWebServer._httpServer = Http.createServer(LoopbackWebServer.onBrowserRequest);
43
- const urlParts = new URL((_a = clientConfiguration.redirectUri) !== null && _a !== void 0 ? _a : ElectronAuthorizationBackend_1.ElectronAuthorizationBackend.defaultRedirectUri);
44
- LoopbackWebServer._httpServer.listen(urlParts.port);
45
- }
46
- /** Add to the authorization state so that the correct response data is used for each request */
47
- static addCorrelationState(state, authEvents) {
48
- return LoopbackWebServer._authState.addState(state, authEvents);
49
- }
50
- /** Stop the web server after the authorization was completed */
51
- static stop() {
52
- if (!LoopbackWebServer._httpServer)
53
- return;
54
- LoopbackWebServer._httpServer.close();
55
- LoopbackWebServer._httpServer = undefined;
56
- }
57
- /** Listen/Handle browser events */
58
- static onBrowserRequest(httpRequest, httpResponse) {
59
- if (!httpRequest.url)
60
- return;
61
- // Parse the request URL to determine the authorization code, state and errors if any
62
- const redirectedUrl = new URL(httpRequest.url, ElectronAuthorizationBackend_1.ElectronAuthorizationBackend.defaultRedirectUri);
63
- const searchParams = redirectedUrl.searchParams;
64
- const state = searchParams.get("state") || undefined;
65
- const code = searchParams.get("code");
66
- const error = searchParams.get("error");
67
- if (!state) {
68
- // ignore irrelevant requests (e.g. favicon.ico)
69
- return;
70
- }
71
- // Look up context for the corresponding outgoing request
72
- const authorizationEvents = LoopbackWebServer._authState.getEvents(state);
73
- if (!authorizationEvents)
74
- return;
75
- // Notify listeners of the code response or error
76
- let authorizationResponse = null;
77
- let authorizationError = null;
78
- if (error) {
79
- const errorUri = searchParams.get("error_uri") || undefined;
80
- const errorDescription = searchParams.get("error_description") || undefined;
81
- authorizationError = { error, error_description: errorDescription, error_uri: errorUri, state }; // eslint-disable-line @typescript-eslint/naming-convention
82
- httpResponse.write("<h1>Sign in error!</h1>"); // TODO: Needs localization
83
- httpResponse.end();
84
- }
85
- else {
86
- authorizationResponse = { code: code, state };
87
- httpResponse.writeHead(200, { "Content-Type": "text/html" }); // eslint-disable-line @typescript-eslint/naming-convention
88
- httpResponse.write("<h1>Sign in was successful!</h1>You can close this browser window and return to the application"); // TODO: Needs localization
89
- httpResponse.end();
90
- }
91
- authorizationEvents.onAuthorizationResponse.raiseEvent(authorizationError, authorizationResponse);
92
- // Handle the authorization completed event
93
- authorizationEvents.onAuthorizationResponseCompleted.addOnce((_authCompletedError) => {
94
- // Stop the web server now that the signin attempt has finished
95
- LoopbackWebServer.stop();
96
- });
97
- }
98
- }
99
- exports.LoopbackWebServer = LoopbackWebServer;
100
- LoopbackWebServer._authState = new AuthorizationState();
101
- //# sourceMappingURL=LoopbackWebServer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LoopbackWebServer.js","sourceRoot":"","sources":["../../../src/backend/LoopbackWebServer.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport * as Http from \"http\";\r\nimport { NativeAppAuthorizationConfiguration } from \"@itwin/core-common\";\r\nimport { AuthorizationErrorJson, AuthorizationResponseJson } from \"@openid/appauth\";\r\nimport { ElectronAuthorizationEvents } from \"./ElectronAuthorizationEvents\";\r\nimport { ElectronAuthorizationBackend } from \"./ElectronAuthorizationBackend\";\r\n\r\ntype StateEventsPair = [string, ElectronAuthorizationEvents];\r\n\r\n/** Utility to manage re-entrancy if there are multiple login attempts */\r\nclass AuthorizationState {\r\n private static _stateEventsMap = [] as StateEventsPair[];\r\n\r\n public addState(state: string, authEvents: ElectronAuthorizationEvents): void {\r\n AuthorizationState._stateEventsMap.push([state, authEvents]);\r\n }\r\n\r\n public removeState(state: string): void {\r\n AuthorizationState._stateEventsMap = AuthorizationState._stateEventsMap.filter((se) => se[0] !== state);\r\n }\r\n\r\n // Get events for a received login response\r\n public getEvents(state: string): ElectronAuthorizationEvents | null {\r\n const stateEventsPair = AuthorizationState._stateEventsMap.find((se) => se[0] === state);\r\n if (stateEventsPair) {\r\n return stateEventsPair[1];\r\n }\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Web server to listen to authorization requests/responses for the DesktopAuthorizationClient\r\n * @internal\r\n */\r\nexport class LoopbackWebServer {\r\n private static _httpServer?: Http.Server;\r\n private static _authState: AuthorizationState = new AuthorizationState();\r\n\r\n /** Start a web server to listen to the browser requests */\r\n public static start(clientConfiguration: NativeAppAuthorizationConfiguration) {\r\n if (LoopbackWebServer._httpServer)\r\n return;\r\n\r\n LoopbackWebServer._httpServer = Http.createServer(LoopbackWebServer.onBrowserRequest);\r\n const urlParts: URL = new URL(clientConfiguration.redirectUri ?? ElectronAuthorizationBackend.defaultRedirectUri);\r\n LoopbackWebServer._httpServer.listen(urlParts.port);\r\n }\r\n\r\n /** Add to the authorization state so that the correct response data is used for each request */\r\n public static addCorrelationState(state: string, authEvents: ElectronAuthorizationEvents): void {\r\n return LoopbackWebServer._authState.addState(state, authEvents);\r\n }\r\n\r\n /** Stop the web server after the authorization was completed */\r\n private static stop() {\r\n if (!LoopbackWebServer._httpServer)\r\n return;\r\n LoopbackWebServer._httpServer.close();\r\n LoopbackWebServer._httpServer = undefined;\r\n }\r\n\r\n /** Listen/Handle browser events */\r\n private static onBrowserRequest(httpRequest: Http.IncomingMessage, httpResponse: Http.ServerResponse): void {\r\n if (!httpRequest.url)\r\n return;\r\n\r\n // Parse the request URL to determine the authorization code, state and errors if any\r\n const redirectedUrl = new URL(httpRequest.url, ElectronAuthorizationBackend.defaultRedirectUri);\r\n const searchParams = redirectedUrl.searchParams;\r\n\r\n const state = searchParams.get(\"state\") || undefined;\r\n const code = searchParams.get(\"code\");\r\n const error = searchParams.get(\"error\");\r\n if (!state) {\r\n // ignore irrelevant requests (e.g. favicon.ico)\r\n return;\r\n }\r\n\r\n // Look up context for the corresponding outgoing request\r\n const authorizationEvents = LoopbackWebServer._authState.getEvents(state);\r\n if (!authorizationEvents)\r\n return;\r\n\r\n // Notify listeners of the code response or error\r\n let authorizationResponse: AuthorizationResponseJson | null = null;\r\n let authorizationError: AuthorizationErrorJson | null = null;\r\n if (error) {\r\n const errorUri = searchParams.get(\"error_uri\") || undefined;\r\n const errorDescription = searchParams.get(\"error_description\") || undefined;\r\n authorizationError = { error, error_description: errorDescription, error_uri: errorUri, state }; // eslint-disable-line @typescript-eslint/naming-convention\r\n httpResponse.write(\"<h1>Sign in error!</h1>\"); // TODO: Needs localization\r\n httpResponse.end();\r\n } else {\r\n authorizationResponse = { code: code!, state };\r\n httpResponse.writeHead(200, { \"Content-Type\": \"text/html\" }); // eslint-disable-line @typescript-eslint/naming-convention\r\n httpResponse.write(\"<h1>Sign in was successful!</h1>You can close this browser window and return to the application\"); // TODO: Needs localization\r\n httpResponse.end();\r\n }\r\n authorizationEvents.onAuthorizationResponse.raiseEvent(authorizationError, authorizationResponse);\r\n\r\n // Handle the authorization completed event\r\n authorizationEvents.onAuthorizationResponseCompleted.addOnce((_authCompletedError?: AuthorizationErrorJson) => {\r\n // Stop the web server now that the signin attempt has finished\r\n LoopbackWebServer.stop();\r\n });\r\n }\r\n}\r\n"]}