@inrupt/solid-client-authn-browser 1.13.4 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Session.d.ts +4 -3
- package/dist/Session.js +21 -17
- package/dist/Session.js.map +1 -1
- package/dist/defaultSession.d.ts +1 -0
- package/dist/defaultSession.js +5 -1
- package/dist/defaultSession.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/solid-client-authn.bundle.js +1 -1
- package/package.json +4 -4
- package/src/Session.spec.ts +242 -114
- package/src/Session.ts +43 -18
- package/src/defaultSession.spec.ts +28 -19
- package/src/defaultSession.ts +15 -1
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inrupt/solid-client-authn-browser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"types": "dist/index",
|
|
6
6
|
"browser": "dist/index.js",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"cross-fetch": "^3.1.5"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@inrupt/oidc-client-ext": "^1.
|
|
29
|
-
"@inrupt/solid-client-authn-core": "^1.
|
|
28
|
+
"@inrupt/oidc-client-ext": "^1.14.0",
|
|
29
|
+
"@inrupt/solid-client-authn-core": "^1.14.0",
|
|
30
30
|
"@types/lodash.clonedeep": "^4.5.6",
|
|
31
31
|
"@types/node": "^18.0.3",
|
|
32
32
|
"@types/uuid": "^9.0.1",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"engines": {
|
|
42
42
|
"node": "^14.0.0 || ^16.0.0"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "fcdfb264ec59cfbeb0e2821ddb7fb716450c13e2"
|
|
45
45
|
}
|
package/src/Session.spec.ts
CHANGED
|
@@ -32,7 +32,7 @@ import { Session } from "./Session";
|
|
|
32
32
|
import { LocalStorageMock } from "./storage/__mocks__/LocalStorage";
|
|
33
33
|
import { mockSessionInfoManager } from "./sessionInfo/__mocks__/SessionInfoManager";
|
|
34
34
|
import { KEY_CURRENT_SESSION, KEY_CURRENT_URL } from "./constant";
|
|
35
|
-
import
|
|
35
|
+
import ClientAuthentication from "./ClientAuthentication";
|
|
36
36
|
|
|
37
37
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
38
38
|
|
|
@@ -408,19 +408,6 @@ describe("Session", () => {
|
|
|
408
408
|
});
|
|
409
409
|
});
|
|
410
410
|
|
|
411
|
-
describe("onError", () => {
|
|
412
|
-
it("calls the registered callback on error", async () => {
|
|
413
|
-
const onErrorCallback = jest.fn();
|
|
414
|
-
const mySession = new Session();
|
|
415
|
-
mySession.onError(onErrorCallback);
|
|
416
|
-
mySession.emit(EVENTS.ERROR, "error", "error_description");
|
|
417
|
-
expect(onErrorCallback).toHaveBeenCalledWith(
|
|
418
|
-
"error",
|
|
419
|
-
"error_description"
|
|
420
|
-
);
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
|
|
424
411
|
describe("silent authentication", () => {
|
|
425
412
|
it("does nothing if no previous session is available", async () => {
|
|
426
413
|
mockLocalStorage({});
|
|
@@ -777,130 +764,271 @@ describe("Session", () => {
|
|
|
777
764
|
});
|
|
778
765
|
});
|
|
779
766
|
|
|
780
|
-
describe("
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
767
|
+
describe("legacy events handlers", () => {
|
|
768
|
+
describe("onError", () => {
|
|
769
|
+
it("calls the registered callback on error", async () => {
|
|
770
|
+
const onErrorCallback = jest.fn();
|
|
771
|
+
const mySession = new Session();
|
|
772
|
+
mySession.onError(onErrorCallback);
|
|
773
|
+
mySession.emit(EVENTS.ERROR, "error", "error_description");
|
|
774
|
+
expect(onErrorCallback).toHaveBeenCalledWith(
|
|
775
|
+
"error",
|
|
776
|
+
"error_description"
|
|
777
|
+
);
|
|
790
778
|
});
|
|
791
|
-
mockLocalStorage({});
|
|
792
|
-
const mySession = new Session({ clientAuthentication });
|
|
793
|
-
mySession.onLogin(myCallback);
|
|
794
|
-
await mySession.handleIncomingRedirect("https://some.url");
|
|
795
|
-
expect(myCallback).toHaveBeenCalled();
|
|
796
779
|
});
|
|
797
780
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
781
|
+
describe("onLogin", () => {
|
|
782
|
+
it("calls the registered callback on login", async () => {
|
|
783
|
+
const myCallback = jest.fn();
|
|
784
|
+
const clientAuthentication = mockClientAuthentication();
|
|
785
|
+
clientAuthentication.handleIncomingRedirect = (
|
|
786
|
+
jest.fn() as any
|
|
787
|
+
).mockResolvedValue({
|
|
788
|
+
isLoggedIn: true,
|
|
789
|
+
sessionId: "a session ID",
|
|
790
|
+
webId: "https://some.webid#them",
|
|
791
|
+
});
|
|
792
|
+
mockLocalStorage({});
|
|
793
|
+
const mySession = new Session({ clientAuthentication });
|
|
794
|
+
mySession.onLogin(myCallback);
|
|
795
|
+
await mySession.handleIncomingRedirect("https://some.url");
|
|
796
|
+
expect(myCallback).toHaveBeenCalled();
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it("does not call the registered callback if login isn't successful", async () => {
|
|
800
|
+
const failCallback = (): void => {
|
|
801
|
+
throw new Error(
|
|
802
|
+
"Should *NOT* call callback - this means test has failed!"
|
|
803
|
+
);
|
|
804
|
+
};
|
|
805
|
+
const clientAuthentication = mockClientAuthentication();
|
|
806
|
+
clientAuthentication.handleIncomingRedirect = jest.fn(
|
|
807
|
+
async (_url: string) => {
|
|
808
|
+
return {
|
|
809
|
+
isLoggedIn: false,
|
|
810
|
+
sessionId: "a session ID",
|
|
811
|
+
webId: "https://some.webid#them",
|
|
812
|
+
};
|
|
813
|
+
}
|
|
802
814
|
);
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
815
|
+
const mySession = new Session({ clientAuthentication });
|
|
816
|
+
mySession.onLogin(failCallback);
|
|
817
|
+
await expect(
|
|
818
|
+
mySession.handleIncomingRedirect("https://some.url")
|
|
819
|
+
).resolves.not.toThrow();
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
it("sets the appropriate information before calling the callback", async () => {
|
|
823
|
+
const clientAuthentication = mockClientAuthentication();
|
|
824
|
+
clientAuthentication.handleIncomingRedirect = jest.fn(
|
|
825
|
+
async (_url: string) => {
|
|
826
|
+
return {
|
|
827
|
+
isLoggedIn: true,
|
|
828
|
+
sessionId: "a session ID",
|
|
829
|
+
webId: "https://some.webid#them",
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
);
|
|
833
|
+
const mySession = new Session({ clientAuthentication });
|
|
834
|
+
const myCallback = jest.fn((): void => {
|
|
835
|
+
expect(mySession.info.webId).toBe("https://some.webid#them");
|
|
836
|
+
});
|
|
837
|
+
mySession.onLogin(myCallback);
|
|
838
|
+
await mySession.handleIncomingRedirect("https://some.url");
|
|
839
|
+
expect(myCallback).toHaveBeenCalled();
|
|
840
|
+
// Verify that the conditional assertion has been called
|
|
841
|
+
expect.assertions(2);
|
|
842
|
+
});
|
|
819
843
|
});
|
|
820
844
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
);
|
|
832
|
-
const mySession = new Session({ clientAuthentication });
|
|
833
|
-
const myCallback = jest.fn((): void => {
|
|
834
|
-
expect(mySession.info.webId).toBe("https://some.webid#them");
|
|
845
|
+
describe("onLogout", () => {
|
|
846
|
+
it("calls the registered callback on logout", async () => {
|
|
847
|
+
const myCallback = jest.fn();
|
|
848
|
+
const mySession = new Session({
|
|
849
|
+
clientAuthentication: mockClientAuthentication(),
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
mySession.onLogout(myCallback);
|
|
853
|
+
await mySession.logout();
|
|
854
|
+
expect(myCallback).toHaveBeenCalled();
|
|
835
855
|
});
|
|
836
|
-
mySession.onLogin(myCallback);
|
|
837
|
-
await mySession.handleIncomingRedirect("https://some.url");
|
|
838
|
-
expect(myCallback).toHaveBeenCalled();
|
|
839
|
-
// Verify that the conditional assertion has been called
|
|
840
|
-
expect.assertions(2);
|
|
841
856
|
});
|
|
842
|
-
});
|
|
843
857
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
858
|
+
describe("onSessionRestore", () => {
|
|
859
|
+
it("calls the registered callback on session restore", async () => {
|
|
860
|
+
// Set our window's location to our test value.
|
|
861
|
+
const defaultLocation = "https://coolSite.com/resource";
|
|
862
|
+
const currentLocation = "https://coolSite.com/redirect";
|
|
863
|
+
|
|
864
|
+
// This pretends we have previously triggered silent authentication and stored
|
|
865
|
+
// the location.
|
|
866
|
+
mockLocalStorage({
|
|
867
|
+
[KEY_CURRENT_URL]: defaultLocation,
|
|
868
|
+
});
|
|
869
|
+
// This acts as the URL the user has been redirected to.
|
|
870
|
+
mockLocation(currentLocation);
|
|
871
|
+
// This pretends the login is successful.
|
|
872
|
+
const clientAuthentication = mockClientAuthentication();
|
|
873
|
+
clientAuthentication.handleIncomingRedirect = (
|
|
874
|
+
jest.fn() as any
|
|
875
|
+
).mockResolvedValue({
|
|
876
|
+
isLoggedIn: true,
|
|
877
|
+
sessionId: "a session ID",
|
|
878
|
+
webId: "https://some.webid#them",
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
const mySession = new Session({
|
|
882
|
+
clientAuthentication,
|
|
883
|
+
});
|
|
884
|
+
const myCallback = (urlBeforeRestore: string): void => {
|
|
885
|
+
expect(urlBeforeRestore).toEqual(defaultLocation);
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
mySession.onSessionRestore(myCallback);
|
|
889
|
+
await mySession.handleIncomingRedirect(currentLocation);
|
|
890
|
+
|
|
891
|
+
// This verifies that the callback has been called
|
|
892
|
+
expect.assertions(1);
|
|
849
893
|
});
|
|
894
|
+
});
|
|
850
895
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
896
|
+
describe("onSessionExpiration", () => {
|
|
897
|
+
it("calls the provided callback when receiving the appropriate event", async () => {
|
|
898
|
+
const myCallback = jest.fn();
|
|
899
|
+
const mySession = new Session({
|
|
900
|
+
clientAuthentication: mockClientAuthentication(),
|
|
901
|
+
});
|
|
902
|
+
mySession.onSessionExpiration(myCallback);
|
|
903
|
+
mySession.emit(EVENTS.SESSION_EXPIRED);
|
|
904
|
+
expect(myCallback).toHaveBeenCalled();
|
|
905
|
+
});
|
|
854
906
|
});
|
|
855
907
|
});
|
|
856
908
|
|
|
857
|
-
describe("
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
909
|
+
describe("events.on", () => {
|
|
910
|
+
describe("login", () => {
|
|
911
|
+
it("calls the registered callback on login", async () => {
|
|
912
|
+
const myCallback = jest.fn();
|
|
913
|
+
const clientAuthentication = mockClientAuthentication();
|
|
914
|
+
clientAuthentication.handleIncomingRedirect = jest
|
|
915
|
+
.fn<ClientAuthentication["handleIncomingRedirect"]>()
|
|
916
|
+
.mockResolvedValue({
|
|
917
|
+
isLoggedIn: true,
|
|
918
|
+
sessionId: "a session ID",
|
|
919
|
+
webId: "https://some.webid#them",
|
|
920
|
+
});
|
|
921
|
+
mockLocalStorage({});
|
|
922
|
+
const mySession = new Session({ clientAuthentication });
|
|
923
|
+
mySession.events.on(EVENTS.LOGIN, myCallback);
|
|
924
|
+
await mySession.handleIncomingRedirect("https://some.url");
|
|
925
|
+
expect(myCallback).toHaveBeenCalled();
|
|
926
|
+
});
|
|
862
927
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
928
|
+
it("does not call the registered callback if login isn't successful", async () => {
|
|
929
|
+
const myCallback = jest.fn();
|
|
930
|
+
const clientAuthentication = mockClientAuthentication();
|
|
931
|
+
clientAuthentication.handleIncomingRedirect = jest
|
|
932
|
+
.fn<ClientAuthentication["handleIncomingRedirect"]>()
|
|
933
|
+
.mockResolvedValue({
|
|
934
|
+
isLoggedIn: true,
|
|
935
|
+
sessionId: "a session ID",
|
|
936
|
+
webId: "https://some.webid#them",
|
|
937
|
+
});
|
|
938
|
+
const mySession = new Session({ clientAuthentication });
|
|
939
|
+
mySession.events.on(EVENTS.LOGIN, myCallback);
|
|
940
|
+
expect(myCallback).not.toHaveBeenCalled();
|
|
867
941
|
});
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
942
|
+
|
|
943
|
+
it("sets the appropriate information before calling the callback", async () => {
|
|
944
|
+
const clientAuthentication = mockClientAuthentication();
|
|
945
|
+
clientAuthentication.handleIncomingRedirect = jest
|
|
946
|
+
.fn<ClientAuthentication["handleIncomingRedirect"]>()
|
|
947
|
+
.mockResolvedValue({
|
|
948
|
+
isLoggedIn: true,
|
|
949
|
+
sessionId: "a session ID",
|
|
950
|
+
webId: "https://some.webid#them",
|
|
951
|
+
});
|
|
952
|
+
const mySession = new Session({ clientAuthentication });
|
|
953
|
+
const myCallback = jest.fn((): void => {
|
|
954
|
+
expect(mySession.info.webId).toBe("https://some.webid#them");
|
|
955
|
+
});
|
|
956
|
+
mySession.events.on(EVENTS.LOGIN, myCallback);
|
|
957
|
+
await mySession.handleIncomingRedirect("https://some.url");
|
|
958
|
+
expect(myCallback).toHaveBeenCalled();
|
|
959
|
+
// Verify that the conditional assertion has been called
|
|
960
|
+
expect.assertions(2);
|
|
878
961
|
});
|
|
962
|
+
});
|
|
879
963
|
|
|
880
|
-
|
|
881
|
-
|
|
964
|
+
describe("logout", () => {
|
|
965
|
+
it("calls the registered callback on logout", async () => {
|
|
966
|
+
const myCallback = jest.fn();
|
|
967
|
+
const mySession = new Session({
|
|
968
|
+
clientAuthentication: mockClientAuthentication(),
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
mySession.events.on(EVENTS.LOGOUT, myCallback);
|
|
972
|
+
await mySession.logout();
|
|
973
|
+
expect(myCallback).toHaveBeenCalled();
|
|
882
974
|
});
|
|
883
|
-
|
|
884
|
-
expect(urlBeforeRestore).toEqual(defaultLocation);
|
|
885
|
-
};
|
|
975
|
+
});
|
|
886
976
|
|
|
887
|
-
|
|
888
|
-
|
|
977
|
+
describe("sessionRestore", () => {
|
|
978
|
+
it("calls the registered callback on session restore", async () => {
|
|
979
|
+
// Set our window's location to our test value.
|
|
980
|
+
const defaultLocation = "https://coolSite.com/resource";
|
|
981
|
+
const currentLocation = "https://coolSite.com/redirect";
|
|
889
982
|
|
|
890
|
-
|
|
891
|
-
|
|
983
|
+
// This pretends we have previously triggered silent authentication and stored
|
|
984
|
+
// the location.
|
|
985
|
+
mockLocalStorage({
|
|
986
|
+
[KEY_CURRENT_URL]: defaultLocation,
|
|
987
|
+
});
|
|
988
|
+
// This acts as the URL the user has been redirected to.
|
|
989
|
+
mockLocation(currentLocation);
|
|
990
|
+
// This pretends the login is successful.
|
|
991
|
+
const clientAuthentication = mockClientAuthentication();
|
|
992
|
+
clientAuthentication.handleIncomingRedirect = jest
|
|
993
|
+
.fn<ClientAuthentication["handleIncomingRedirect"]>()
|
|
994
|
+
.mockResolvedValue({
|
|
995
|
+
isLoggedIn: true,
|
|
996
|
+
sessionId: "a session ID",
|
|
997
|
+
webId: "https://some.webid#them",
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
const mySession = new Session({
|
|
1001
|
+
clientAuthentication,
|
|
1002
|
+
});
|
|
1003
|
+
const myCallback = (urlBeforeRestore: string): void => {
|
|
1004
|
+
expect(urlBeforeRestore).toEqual(defaultLocation);
|
|
1005
|
+
};
|
|
1006
|
+
|
|
1007
|
+
mySession.events.on(EVENTS.SESSION_RESTORED, myCallback);
|
|
1008
|
+
await mySession.handleIncomingRedirect(currentLocation);
|
|
1009
|
+
|
|
1010
|
+
// This verifies that the callback has been called
|
|
1011
|
+
expect.assertions(1);
|
|
1012
|
+
});
|
|
892
1013
|
});
|
|
893
1014
|
});
|
|
894
1015
|
|
|
895
|
-
describe("
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
mySession.
|
|
902
|
-
|
|
903
|
-
|
|
1016
|
+
describe("proxies events to the session", () => {
|
|
1017
|
+
// This describe block is only required as long as Session extends the EventEmitter
|
|
1018
|
+
// class.
|
|
1019
|
+
it("proxies the EventEmitter calls from events to the session object", () => {
|
|
1020
|
+
const mySession = new Session();
|
|
1021
|
+
const spiedOn = jest.spyOn(mySession, "on");
|
|
1022
|
+
mySession.events.on("login", jest.fn());
|
|
1023
|
+
expect(spiedOn).toHaveBeenCalled();
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it("throws on calls from events which aren't part of the EventEmitter interface", () => {
|
|
1027
|
+
const mySession = new Session();
|
|
1028
|
+
// @ts-expect-error onLogin is a function on Session, and not SessionEventEmitter
|
|
1029
|
+
expect(() => mySession.events.onLogin(jest.fn())).toThrow(
|
|
1030
|
+
"[onLogin] is not supported"
|
|
1031
|
+
);
|
|
904
1032
|
});
|
|
905
1033
|
});
|
|
906
1034
|
});
|
package/src/Session.ts
CHANGED
|
@@ -22,14 +22,17 @@
|
|
|
22
22
|
/**
|
|
23
23
|
* @hidden
|
|
24
24
|
*/
|
|
25
|
-
import { EventEmitter } from "events";
|
|
26
25
|
import {
|
|
27
26
|
EVENTS,
|
|
28
27
|
ILoginInputOptions,
|
|
29
28
|
ISessionInfo,
|
|
30
29
|
IStorage,
|
|
30
|
+
IHasSessionEventListener,
|
|
31
|
+
ISessionEventListener,
|
|
32
|
+
buildProxyHandler,
|
|
31
33
|
} from "@inrupt/solid-client-authn-core";
|
|
32
34
|
import { v4 } from "uuid";
|
|
35
|
+
import EventEmitter from "events";
|
|
33
36
|
import ClientAuthentication from "./ClientAuthentication";
|
|
34
37
|
import { getClientAuthenticationWithDependencies } from "./dependencies";
|
|
35
38
|
import { KEY_CURRENT_SESSION, KEY_CURRENT_URL } from "./constant";
|
|
@@ -116,7 +119,7 @@ export async function silentlyAuthenticate(
|
|
|
116
119
|
clientSecret: storedSessionInfo.clientAppSecret,
|
|
117
120
|
tokenType: storedSessionInfo.tokenType ?? "DPoP",
|
|
118
121
|
},
|
|
119
|
-
session
|
|
122
|
+
session.events
|
|
120
123
|
);
|
|
121
124
|
return true;
|
|
122
125
|
}
|
|
@@ -132,12 +135,19 @@ function isLoggedIn(
|
|
|
132
135
|
/**
|
|
133
136
|
* A {@link Session} object represents a user's session on an application. The session holds state, as it stores information enabling acces to private resources after login for instance.
|
|
134
137
|
*/
|
|
135
|
-
export class Session extends EventEmitter {
|
|
138
|
+
export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
136
139
|
/**
|
|
137
140
|
* Information regarding the current session.
|
|
138
141
|
*/
|
|
139
142
|
public readonly info: ISessionInfo;
|
|
140
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Session attribute exposing the EventEmitter interface, to listen on session
|
|
146
|
+
* events such as login, logout, etc.
|
|
147
|
+
* @since 1.15.0
|
|
148
|
+
*/
|
|
149
|
+
public readonly events: ISessionEventListener;
|
|
150
|
+
|
|
141
151
|
private clientAuthentication: ClientAuthentication;
|
|
142
152
|
|
|
143
153
|
private tokenRequestInProgress = false;
|
|
@@ -162,7 +172,17 @@ export class Session extends EventEmitter {
|
|
|
162
172
|
sessionId: string | undefined = undefined
|
|
163
173
|
) {
|
|
164
174
|
super();
|
|
165
|
-
|
|
175
|
+
// Until Session no longer implements EventEmitter, this.events is just a proxy
|
|
176
|
+
// to this (with some interface filtering). When we make the breaking change,
|
|
177
|
+
// this.events will be a regular EventEmitter (implementing ISessionEventEmitter):
|
|
178
|
+
// this.events = new EventEmitter();
|
|
179
|
+
this.events = new Proxy(
|
|
180
|
+
this,
|
|
181
|
+
buildProxyHandler(
|
|
182
|
+
Session.prototype,
|
|
183
|
+
"events only implements ISessionEventListener"
|
|
184
|
+
)
|
|
185
|
+
);
|
|
166
186
|
if (sessionOptions.clientAuthentication) {
|
|
167
187
|
this.clientAuthentication = sessionOptions.clientAuthentication;
|
|
168
188
|
} else if (sessionOptions.secureStorage && sessionOptions.insecureStorage) {
|
|
@@ -191,13 +211,13 @@ export class Session extends EventEmitter {
|
|
|
191
211
|
// enable silent refresh. The current session ID specifically stored in 'localStorage'
|
|
192
212
|
// (as opposed to using our storage abstraction layer) because it is only
|
|
193
213
|
// used in a browser-specific mechanism.
|
|
194
|
-
this.on(EVENTS.LOGIN, () =>
|
|
214
|
+
this.events.on(EVENTS.LOGIN, () =>
|
|
195
215
|
window.localStorage.setItem(KEY_CURRENT_SESSION, this.info.sessionId)
|
|
196
216
|
);
|
|
197
217
|
|
|
198
|
-
this.on(EVENTS.SESSION_EXPIRED, () => this.internalLogout(false));
|
|
218
|
+
this.events.on(EVENTS.SESSION_EXPIRED, () => this.internalLogout(false));
|
|
199
219
|
|
|
200
|
-
this.on(EVENTS.ERROR, () => this.internalLogout(false));
|
|
220
|
+
this.events.on(EVENTS.ERROR, () => this.internalLogout(false));
|
|
201
221
|
}
|
|
202
222
|
|
|
203
223
|
/**
|
|
@@ -216,7 +236,7 @@ export class Session extends EventEmitter {
|
|
|
216
236
|
// Defaults the token type to DPoP
|
|
217
237
|
tokenType: options.tokenType ?? "DPoP",
|
|
218
238
|
},
|
|
219
|
-
this
|
|
239
|
+
this.events
|
|
220
240
|
);
|
|
221
241
|
// `login` redirects the user away from the app,
|
|
222
242
|
// so unless it throws an error, there is no code that should run afterwards
|
|
@@ -250,7 +270,7 @@ export class Session extends EventEmitter {
|
|
|
250
270
|
await this.clientAuthentication.logout(this.info.sessionId);
|
|
251
271
|
this.info.isLoggedIn = false;
|
|
252
272
|
if (emitSignal) {
|
|
253
|
-
this.emit(EVENTS.LOGOUT);
|
|
273
|
+
(this.events as EventEmitter).emit(EVENTS.LOGOUT);
|
|
254
274
|
}
|
|
255
275
|
};
|
|
256
276
|
|
|
@@ -282,7 +302,7 @@ export class Session extends EventEmitter {
|
|
|
282
302
|
this.tokenRequestInProgress = true;
|
|
283
303
|
const sessionInfo = await this.clientAuthentication.handleIncomingRedirect(
|
|
284
304
|
url,
|
|
285
|
-
this
|
|
305
|
+
this.events
|
|
286
306
|
);
|
|
287
307
|
if (isLoggedIn(sessionInfo)) {
|
|
288
308
|
this.setSessionInfo(sessionInfo);
|
|
@@ -290,13 +310,13 @@ export class Session extends EventEmitter {
|
|
|
290
310
|
if (currentUrl === null) {
|
|
291
311
|
// The login event can only be triggered **after** the user has been
|
|
292
312
|
// redirected from the IdP with access and ID tokens.
|
|
293
|
-
this.emit(EVENTS.LOGIN);
|
|
313
|
+
(this.events as EventEmitter).emit(EVENTS.LOGIN);
|
|
294
314
|
} else {
|
|
295
315
|
// If an URL is stored in local storage, we are being logged in after a
|
|
296
316
|
// silent authentication, so remove our currently stored URL location
|
|
297
317
|
// to clean up our state now that we are completing the re-login process.
|
|
298
318
|
window.localStorage.removeItem(KEY_CURRENT_URL);
|
|
299
|
-
this.emit(EVENTS.SESSION_RESTORED, currentUrl);
|
|
319
|
+
(this.events as EventEmitter).emit(EVENTS.SESSION_RESTORED, currentUrl);
|
|
300
320
|
}
|
|
301
321
|
} else if (options.restorePreviousSession === true) {
|
|
302
322
|
// Silent authentication happens after a refresh, which means there are no
|
|
@@ -332,18 +352,20 @@ export class Session extends EventEmitter {
|
|
|
332
352
|
* The callback is called when {@link handleIncomingRedirect} completes successfully.
|
|
333
353
|
*
|
|
334
354
|
* @param callback The function called when a user completes login.
|
|
355
|
+
* @deprecated Prefer session.events.on(EVENTS.LOGIN, callback)
|
|
335
356
|
*/
|
|
336
357
|
onLogin(callback: () => unknown): void {
|
|
337
|
-
this.on(EVENTS.LOGIN, callback);
|
|
358
|
+
this.events.on(EVENTS.LOGIN, callback);
|
|
338
359
|
}
|
|
339
360
|
|
|
340
361
|
/**
|
|
341
362
|
* Register a callback function to be called when a user logs out:
|
|
342
363
|
*
|
|
343
364
|
* @param callback The function called when a user completes logout.
|
|
365
|
+
* @deprecated Prefer session.events.on(EVENTS.LOGOUT, callback)
|
|
344
366
|
*/
|
|
345
367
|
onLogout(callback: () => unknown): void {
|
|
346
|
-
this.on(EVENTS.LOGOUT, callback);
|
|
368
|
+
this.events.on(EVENTS.LOGOUT, callback);
|
|
347
369
|
}
|
|
348
370
|
|
|
349
371
|
/**
|
|
@@ -351,6 +373,7 @@ export class Session extends EventEmitter {
|
|
|
351
373
|
*
|
|
352
374
|
* @param callback The function called when an error occurs.
|
|
353
375
|
* @since 1.11.0
|
|
376
|
+
* @deprecated Prefer session.events.on(EVENTS.ERROR, callback)
|
|
354
377
|
*/
|
|
355
378
|
onError(
|
|
356
379
|
callback: (
|
|
@@ -358,7 +381,7 @@ export class Session extends EventEmitter {
|
|
|
358
381
|
errorDescription?: string | null
|
|
359
382
|
) => unknown
|
|
360
383
|
): void {
|
|
361
|
-
this.on(EVENTS.ERROR, callback);
|
|
384
|
+
this.events.on(EVENTS.ERROR, callback);
|
|
362
385
|
}
|
|
363
386
|
|
|
364
387
|
/**
|
|
@@ -368,9 +391,10 @@ export class Session extends EventEmitter {
|
|
|
368
391
|
* at the time the session was restored.
|
|
369
392
|
*
|
|
370
393
|
* @param callback The function called when a user's already logged-in session is restored, e.g., after a silent authentication is completed after a page refresh.
|
|
394
|
+
* @deprecated Prefer session.events.on(EVENTS.SESSION_RESTORED, callback)
|
|
371
395
|
*/
|
|
372
396
|
onSessionRestore(callback: (currentUrl: string) => unknown): void {
|
|
373
|
-
this.on(EVENTS.SESSION_RESTORED, callback);
|
|
397
|
+
this.events.on(EVENTS.SESSION_RESTORED, callback);
|
|
374
398
|
}
|
|
375
399
|
|
|
376
400
|
/**
|
|
@@ -378,9 +402,10 @@ export class Session extends EventEmitter {
|
|
|
378
402
|
* make authenticated requests, but following a user logout.
|
|
379
403
|
* @param callback The function that runs on session expiration.
|
|
380
404
|
* @since 1.11.0
|
|
405
|
+
* @deprecated Prefer session.events.on(EVENTS.SESSION_EXPIRED, callback)
|
|
381
406
|
*/
|
|
382
407
|
onSessionExpiration(callback: () => unknown): void {
|
|
383
|
-
this.on(EVENTS.SESSION_EXPIRED, callback);
|
|
408
|
+
this.events.on(EVENTS.SESSION_EXPIRED, callback);
|
|
384
409
|
}
|
|
385
410
|
|
|
386
411
|
private setSessionInfo(
|
|
@@ -390,7 +415,7 @@ export class Session extends EventEmitter {
|
|
|
390
415
|
this.info.webId = sessionInfo.webId;
|
|
391
416
|
this.info.sessionId = sessionInfo.sessionId;
|
|
392
417
|
this.info.expirationDate = sessionInfo.expirationDate;
|
|
393
|
-
this.on(EVENTS.SESSION_EXTENDED, (expiresIn: number) => {
|
|
418
|
+
this.events.on(EVENTS.SESSION_EXTENDED, (expiresIn: number) => {
|
|
394
419
|
this.info.expirationDate = Date.now() + expiresIn * 1000;
|
|
395
420
|
});
|
|
396
421
|
}
|