-
Notifications
You must be signed in to change notification settings - Fork 137
/
Copy pathIdentityValidationHandler.ts
141 lines (123 loc) · 5.8 KB
/
IdentityValidationHandler.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { GetAgentParams, AgentError } from '@finos/fdc3-standard';
import { retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails';
import { Logger } from '../util/Logger';
import { BrowserTypes } from '@finos/fdc3-schema';
const {
isWebConnectionProtocol5ValidateAppIdentitySuccessResponse,
isWebConnectionProtocol5ValidateAppIdentityFailedResponse,
} = BrowserTypes;
type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity;
type WebConnectionProtocol5ValidateAppIdentitySuccessResponse =
BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse;
type WebConnectionProtocolMessage = BrowserTypes.WebConnectionProtocolMessage;
/** Timeout allowed for id validation to occur and for the DA to respond with details.
* This is additional to the app's specified timeout for discovery - we have already
* found an agent at that point we are just finishing setting up the connection. */
const ID_VALIDATION_TIMEOUT = 5000;
export class IdentityValidationHandler {
constructor(mp: MessagePort, options: GetAgentParams, connectionAttemptUuid: string) {
this.messagePort = mp;
this.options = options;
this.connectionAttemptUuid = connectionAttemptUuid;
this.idValidationResponseListener = null;
}
/** Reference to the MessagePort received. Used to remove listeners when cancelling. */
messagePort: MessagePort;
/** Parameters passed to getAgent */
options: GetAgentParams;
/** UUID used to filter messages */
connectionAttemptUuid: string;
/** Event listener for ID validation response from Desktop Agents over the MessagePort.
* Used to remove them when no longer needed.
* Initialized during the id validation step.
*/
idValidationResponseListener: ((event: MessageEvent<WebConnectionProtocolMessage>) => void) | null;
/**
* Starts the connection process off by sending a hello message
*/
sendIdValidationMessage() {
const actualUrl = globalThis.window.location.href;
const identityUrl = this.options.identityUrl ?? actualUrl;
const requestMessage: WebConnectionProtocol4ValidateAppIdentity = {
type: 'WCP4ValidateAppIdentity',
meta: {
connectionAttemptUuid: this.connectionAttemptUuid,
timestamp: new Date(),
},
payload: {
identityUrl,
actualUrl,
},
};
const persistedDetails = retrieveDesktopAgentDetails(identityUrl);
if (persistedDetails) {
requestMessage.payload.instanceId = persistedDetails.instanceId;
requestMessage.payload.instanceUuid = persistedDetails.instanceUuid;
}
this.messagePort.postMessage(requestMessage);
}
/** Listen for WCP responses over the message port to identity validation messages. */
listenForIDValidationResponses(): Promise<WebConnectionProtocol5ValidateAppIdentitySuccessResponse> {
return new Promise<WebConnectionProtocol5ValidateAppIdentitySuccessResponse>((resolve, reject) => {
// setup listener for message and retrieve JS URL from it
this.idValidationResponseListener = (event: MessageEvent<WebConnectionProtocolMessage>) => {
const data = event.data;
if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) {
if (isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(data)) {
//passed validation
clearTimeout(timeout);
if (this.idValidationResponseListener) {
//remove the event listener as we've received a messagePort to use
this.messagePort.removeEventListener('message', this.idValidationResponseListener);
}
Logger.debug(
`IdentityValidationHandler: Validated app identity, appId: ${data.payload.appId}, instanceId: ${data.payload.instanceId}`
);
resolve(data);
} else if (isWebConnectionProtocol5ValidateAppIdentityFailedResponse(data)) {
//failed validation...
clearTimeout(timeout);
if (this.idValidationResponseListener) {
//remove the event listener as we've received a messagePort to use
this.messagePort.removeEventListener('message', this.idValidationResponseListener);
}
Logger.error(
`IdentityValidationHandler: App identity validation failed: ${data.payload.message ?? 'No reason given'}`
);
reject(AgentError.AccessDenied);
} else {
Logger.debug(
`IdentityValidationHandler: Ignoring message unexpected message in PostMessageLoader (because its not a WCP5 message).`,
data
);
}
} else {
Logger.warn(
`IdentityValidationHandler: Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`,
data
);
}
};
//listening on a message port
this.messagePort.addEventListener('message', this.idValidationResponseListener);
//timeout for id validation only
const timeout = setTimeout(() => {
Logger.warn(`IdentityValidationHandler: Identity validation timed out`);
if (this.idValidationResponseListener) {
//remove the event listener as we won't proceed further
this.messagePort.removeEventListener('message', this.idValidationResponseListener);
}
Logger.error(
`The Desktop Agent didn't respond to ID validation within ${ID_VALIDATION_TIMEOUT / 1000} seconds`
);
reject(AgentError.ErrorOnConnect);
}, ID_VALIDATION_TIMEOUT);
});
}
cancel(): void {
if (this.idValidationResponseListener) {
this.messagePort.removeEventListener('message', this.idValidationResponseListener);
}
//TODO: cancel any timeouts and reject any returned promises
}
}