UNPKG

angular-simple-oidc

Version:

Angular Library implementing Open Id Connect specification. Code Flow, Refresh Tokens, Session Management, Discovery Document.

101 lines 13.8 kB
import { Injectable } from '@angular/core'; import { IssuerValidationError, SubjectValidationError, IssuedAtValidationError, AudienceValidationError, AuthTimeValidationError, AuthorizedPartyValidationError } from './refresh-token-validation-errors'; /** * its iss Claim Value MUST be the same as in the ID Token issued when the original authentication occurred, * its sub Claim Value MUST be the same as in the ID Token issued when the original authentication occurred, * its iat Claim MUST represent the time that the new ID Token is issued, * its aud Claim Value MUST be the same as in the ID Token issued when the original authentication occurred, * if the ID Token contains an auth_time Claim, its value MUST represent the time * of the original authentication - not the time that the new ID token is issued, * its azp Claim Value MUST be the same as in the ID Token issued when the original authentication occurred; * if no azp Claim was present in the original ID Token, one MUST NOT be present in the new ID Token, and * otherwise, the same rules apply as apply when issuing an ID Token at the time of the original authentication. */ export class RefreshTokenValidationService { /** * Perform validations according to * 12.2. Successful Refresh Response * https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens */ validateIdToken(originalIdToken, newIdToken) { this.validateIssuer(originalIdToken, newIdToken); this.validateSubject(originalIdToken, newIdToken); this.validateIssuedAt(originalIdToken, newIdToken); this.validateAudience(originalIdToken, newIdToken); this.validateAuthTime(originalIdToken, newIdToken); this.validateAuthorizedParty(originalIdToken, newIdToken); } /** * its iss Claim Value MUST be the same as in the ID Token issued when the original authentication occurred */ validateIssuer(originalIdToken, newIdToken) { if (originalIdToken.iss !== newIdToken.iss) { throw new IssuerValidationError(originalIdToken.iss, newIdToken.iss, { originalIdToken, newIdToken }); } } /** * its sub Claim Value MUST be the same as in the ID Token issued when the original authentication occurred, */ validateSubject(originalIdToken, newIdToken) { if (originalIdToken.sub !== newIdToken.sub) { throw new SubjectValidationError(originalIdToken.sub, newIdToken.sub, { originalIdToken, newIdToken }); } } /** * its iat Claim MUST represent the time that the new ID Token is issued, */ validateIssuedAt(originalIdToken, newIdToken) { if (!(newIdToken.iat >= originalIdToken.iat)) { throw new IssuedAtValidationError({ originalIdToken, newIdToken }); } } /** * its aud Claim Value MUST be the same as in the ID Token issued when the original authentication occurred, */ validateAudience(originalIdToken, newIdToken) { if (originalIdToken.aud !== newIdToken.aud) { throw new AudienceValidationError({ originalIdToken, newIdToken }); } } /** * if the ID Token contains an auth_time Claim, its value MUST represent * the time of the original authentication - not the time that the new ID token is issued, */ validateAuthTime(originalIdToken, newIdToken) { if (newIdToken.auth_time && (originalIdToken.auth_time !== newIdToken.auth_time)) { throw new AuthTimeValidationError({ originalIdToken, newIdToken }); } } /** * its azp Claim Value MUST be the same as in the ID Token issued when the original authentication occurred; * if no azp Claim was present in the original ID Token, one MUST NOT be present in the new ID Token, and * otherwise, the same rules apply as apply when issuing an ID Token at the time of the original authentication. */ validateAuthorizedParty(originalIdToken, newIdToken) { if (originalIdToken.azp !== newIdToken.azp) { throw new AuthorizedPartyValidationError({ originalIdToken, newIdToken }); } } } RefreshTokenValidationService.decorators = [ { type: Injectable } ]; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmcmVzaC10b2tlbi12YWxpZGF0aW9uLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLXNpbXBsZS1vaWRjL2NvcmUvbGliL3JlZnJlc2gtdG9rZW4vcmVmcmVzaC10b2tlbi12YWxpZGF0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQ0gscUJBQXFCLEVBQ3JCLHNCQUFzQixFQUN0Qix1QkFBdUIsRUFDdkIsdUJBQXVCLEVBQ3ZCLHVCQUF1QixFQUN2Qiw4QkFBOEIsRUFDakMsTUFBTSxtQ0FBbUMsQ0FBQztBQUUzQzs7Ozs7Ozs7OztHQVVHO0FBRUgsTUFBTSxPQUFPLDZCQUE2QjtJQUV0Qzs7OztPQUlHO0lBQ0ksZUFBZSxDQUFDLGVBQXFDLEVBQUUsVUFBZ0M7UUFDMUYsSUFBSSxDQUFDLGNBQWMsQ0FBQyxlQUFlLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxlQUFlLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLGVBQWUsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNuRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLHVCQUF1QixDQUFDLGVBQWUsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxjQUFjLENBQUMsZUFBcUMsRUFBRSxVQUFnQztRQUN6RixJQUFJLGVBQWUsQ0FBQyxHQUFHLEtBQUssVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUN4QyxNQUFNLElBQUkscUJBQXFCLENBQUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUNqRSxlQUFlO2dCQUNmLFVBQVU7YUFDYixDQUFDLENBQUM7U0FDTjtJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNJLGVBQWUsQ0FBQyxlQUFxQyxFQUFFLFVBQWdDO1FBQzFGLElBQUksZUFBZSxDQUFDLEdBQUcsS0FBSyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ3hDLE1BQU0sSUFBSSxzQkFBc0IsQ0FBQyxlQUFlLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2xFLGVBQWU7Z0JBQ2YsVUFBVTthQUNiLENBQUMsQ0FBQztTQUNOO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ksZ0JBQWdCLENBQUMsZUFBcUMsRUFBRSxVQUFnQztRQUMzRixJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxJQUFJLGVBQWUsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUMxQyxNQUFNLElBQUksdUJBQXVCLENBQUM7Z0JBQzlCLGVBQWU7Z0JBQ2YsVUFBVTthQUNiLENBQUMsQ0FBQztTQUNOO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ksZ0JBQWdCLENBQUMsZUFBcUMsRUFBRSxVQUFnQztRQUMzRixJQUFJLGVBQWUsQ0FBQyxHQUFHLEtBQUssVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUN4QyxNQUFNLElBQUksdUJBQXVCLENBQUM7Z0JBQzlCLGVBQWU7Z0JBQ2YsVUFBVTthQUNiLENBQUMsQ0FBQztTQUNOO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNJLGdCQUFnQixDQUFDLGVBQXFDLEVBQUUsVUFBZ0M7UUFDM0YsSUFBSSxVQUFVLENBQUMsU0FBUyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsS0FBSyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUU7WUFDOUUsTUFBTSxJQUFJLHVCQUF1QixDQUFDO2dCQUM5QixlQUFlO2dCQUNmLFVBQVU7YUFDYixDQUFDLENBQUM7U0FDTjtJQUNMLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksdUJBQXVCLENBQUMsZUFBcUMsRUFBRSxVQUFnQztRQUNsRyxJQUFJLGVBQWUsQ0FBQyxHQUFHLEtBQUssVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUN4QyxNQUFNLElBQUksOEJBQThCLENBQUM7Z0JBQ3JDLGVBQWU7Z0JBQ2YsVUFBVTthQUNiLENBQUMsQ0FBQztTQUNOO0lBQ0wsQ0FBQzs7O1lBMUZKLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBEZWNvZGVkSWRlbnRpdHlUb2tlbiB9IGZyb20gJy4uL21vZGVscyc7XG5pbXBvcnQge1xuICAgIElzc3VlclZhbGlkYXRpb25FcnJvcixcbiAgICBTdWJqZWN0VmFsaWRhdGlvbkVycm9yLFxuICAgIElzc3VlZEF0VmFsaWRhdGlvbkVycm9yLFxuICAgIEF1ZGllbmNlVmFsaWRhdGlvbkVycm9yLFxuICAgIEF1dGhUaW1lVmFsaWRhdGlvbkVycm9yLFxuICAgIEF1dGhvcml6ZWRQYXJ0eVZhbGlkYXRpb25FcnJvclxufSBmcm9tICcuL3JlZnJlc2gtdG9rZW4tdmFsaWRhdGlvbi1lcnJvcnMnO1xuXG4vKipcbiAqIGl0cyBpc3MgQ2xhaW0gVmFsdWUgTVVTVCBiZSB0aGUgc2FtZSBhcyBpbiB0aGUgSUQgVG9rZW4gaXNzdWVkIHdoZW4gdGhlIG9yaWdpbmFsIGF1dGhlbnRpY2F0aW9uIG9jY3VycmVkLFxuICogaXRzIHN1YiBDbGFpbSBWYWx1ZSBNVVNUIGJlIHRoZSBzYW1lIGFzIGluIHRoZSBJRCBUb2tlbiBpc3N1ZWQgd2hlbiB0aGUgb3JpZ2luYWwgYXV0aGVudGljYXRpb24gb2NjdXJyZWQsXG4gKiBpdHMgaWF0IENsYWltIE1VU1QgcmVwcmVzZW50IHRoZSB0aW1lIHRoYXQgdGhlIG5ldyBJRCBUb2tlbiBpcyBpc3N1ZWQsXG4gKiBpdHMgYXVkIENsYWltIFZhbHVlIE1VU1QgYmUgdGhlIHNhbWUgYXMgaW4gdGhlIElEIFRva2VuIGlzc3VlZCB3aGVuIHRoZSBvcmlnaW5hbCBhdXRoZW50aWNhdGlvbiBvY2N1cnJlZCxcbiAqIGlmIHRoZSBJRCBUb2tlbiBjb250YWlucyBhbiBhdXRoX3RpbWUgQ2xhaW0sIGl0cyB2YWx1ZSBNVVNUIHJlcHJlc2VudCB0aGUgdGltZVxuICogb2YgdGhlIG9yaWdpbmFsIGF1dGhlbnRpY2F0aW9uIC0gbm90IHRoZSB0aW1lIHRoYXQgdGhlIG5ldyBJRCB0b2tlbiBpcyBpc3N1ZWQsXG4gKiBpdHMgYXpwIENsYWltIFZhbHVlIE1VU1QgYmUgdGhlIHNhbWUgYXMgaW4gdGhlIElEIFRva2VuIGlzc3VlZCB3aGVuIHRoZSBvcmlnaW5hbCBhdXRoZW50aWNhdGlvbiBvY2N1cnJlZDtcbiAqIGlmIG5vIGF6cCBDbGFpbSB3YXMgcHJlc2VudCBpbiB0aGUgb3JpZ2luYWwgSUQgVG9rZW4sIG9uZSBNVVNUIE5PVCBiZSBwcmVzZW50IGluIHRoZSBuZXcgSUQgVG9rZW4sIGFuZFxuICogb3RoZXJ3aXNlLCB0aGUgc2FtZSBydWxlcyBhcHBseSBhcyBhcHBseSB3aGVuIGlzc3VpbmcgYW4gSUQgVG9rZW4gYXQgdGhlIHRpbWUgb2YgdGhlIG9yaWdpbmFsIGF1dGhlbnRpY2F0aW9uLlxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgUmVmcmVzaFRva2VuVmFsaWRhdGlvblNlcnZpY2Uge1xuXG4gICAgLyoqXG4gICAgICogUGVyZm9ybSB2YWxpZGF0aW9ucyBhY2NvcmRpbmcgdG9cbiAgICAgKiAxMi4yLiAgU3VjY2Vzc2Z1bCBSZWZyZXNoIFJlc3BvbnNlXG4gICAgICogaHR0cHM6Ly9vcGVuaWQubmV0L3NwZWNzL29wZW5pZC1jb25uZWN0LWNvcmUtMV8wLmh0bWwjUmVmcmVzaFRva2Vuc1xuICAgICAqL1xuICAgIHB1YmxpYyB2YWxpZGF0ZUlkVG9rZW4ob3JpZ2luYWxJZFRva2VuOiBEZWNvZGVkSWRlbnRpdHlUb2tlbiwgbmV3SWRUb2tlbjogRGVjb2RlZElkZW50aXR5VG9rZW4pIHtcbiAgICAgICAgdGhpcy52YWxpZGF0ZUlzc3VlcihvcmlnaW5hbElkVG9rZW4sIG5ld0lkVG9rZW4pO1xuICAgICAgICB0aGlzLnZhbGlkYXRlU3ViamVjdChvcmlnaW5hbElkVG9rZW4sIG5ld0lkVG9rZW4pO1xuICAgICAgICB0aGlzLnZhbGlkYXRlSXNzdWVkQXQob3JpZ2luYWxJZFRva2VuLCBuZXdJZFRva2VuKTtcbiAgICAgICAgdGhpcy52YWxpZGF0ZUF1ZGllbmNlKG9yaWdpbmFsSWRUb2tlbiwgbmV3SWRUb2tlbik7XG4gICAgICAgIHRoaXMudmFsaWRhdGVBdXRoVGltZShvcmlnaW5hbElkVG9rZW4sIG5ld0lkVG9rZW4pO1xuICAgICAgICB0aGlzLnZhbGlkYXRlQXV0aG9yaXplZFBhcnR5KG9yaWdpbmFsSWRUb2tlbiwgbmV3SWRUb2tlbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaXRzIGlzcyBDbGFpbSBWYWx1ZSBNVVNUIGJlIHRoZSBzYW1lIGFzIGluIHRoZSBJRCBUb2tlbiBpc3N1ZWQgd2hlbiB0aGUgb3JpZ2luYWwgYXV0aGVudGljYXRpb24gb2NjdXJyZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgdmFsaWRhdGVJc3N1ZXIob3JpZ2luYWxJZFRva2VuOiBEZWNvZGVkSWRlbnRpdHlUb2tlbiwgbmV3SWRUb2tlbjogRGVjb2RlZElkZW50aXR5VG9rZW4pIHtcbiAgICAgICAgaWYgKG9yaWdpbmFsSWRUb2tlbi5pc3MgIT09IG5ld0lkVG9rZW4uaXNzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgSXNzdWVyVmFsaWRhdGlvbkVycm9yKG9yaWdpbmFsSWRUb2tlbi5pc3MsIG5ld0lkVG9rZW4uaXNzLCB7XG4gICAgICAgICAgICAgICAgb3JpZ2luYWxJZFRva2VuLFxuICAgICAgICAgICAgICAgIG5ld0lkVG9rZW5cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaXRzIHN1YiBDbGFpbSBWYWx1ZSBNVVNUIGJlIHRoZSBzYW1lIGFzIGluIHRoZSBJRCBUb2tlbiBpc3N1ZWQgd2hlbiB0aGUgb3JpZ2luYWwgYXV0aGVudGljYXRpb24gb2NjdXJyZWQsXG4gICAgICovXG4gICAgcHVibGljIHZhbGlkYXRlU3ViamVjdChvcmlnaW5hbElkVG9rZW46IERlY29kZWRJZGVudGl0eVRva2VuLCBuZXdJZFRva2VuOiBEZWNvZGVkSWRlbnRpdHlUb2tlbikge1xuICAgICAgICBpZiAob3JpZ2luYWxJZFRva2VuLnN1YiAhPT0gbmV3SWRUb2tlbi5zdWIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBTdWJqZWN0VmFsaWRhdGlvbkVycm9yKG9yaWdpbmFsSWRUb2tlbi5zdWIsIG5ld0lkVG9rZW4uc3ViLCB7XG4gICAgICAgICAgICAgICAgb3JpZ2luYWxJZFRva2VuLFxuICAgICAgICAgICAgICAgIG5ld0lkVG9rZW5cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaXRzIGlhdCBDbGFpbSBNVVNUIHJlcHJlc2VudCB0aGUgdGltZSB0aGF0IHRoZSBuZXcgSUQgVG9rZW4gaXMgaXNzdWVkLFxuICAgICAqL1xuICAgIHB1YmxpYyB2YWxpZGF0ZUlzc3VlZEF0KG9yaWdpbmFsSWRUb2tlbjogRGVjb2RlZElkZW50aXR5VG9rZW4sIG5ld0lkVG9rZW46IERlY29kZWRJZGVudGl0eVRva2VuKSB7XG4gICAgICAgIGlmICghKG5ld0lkVG9rZW4uaWF0ID49IG9yaWdpbmFsSWRUb2tlbi5pYXQpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgSXNzdWVkQXRWYWxpZGF0aW9uRXJyb3Ioe1xuICAgICAgICAgICAgICAgIG9yaWdpbmFsSWRUb2tlbixcbiAgICAgICAgICAgICAgICBuZXdJZFRva2VuXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGl0cyBhdWQgQ2xhaW0gVmFsdWUgTVVTVCBiZSB0aGUgc2FtZSBhcyBpbiB0aGUgSUQgVG9rZW4gaXNzdWVkIHdoZW4gdGhlIG9yaWdpbmFsIGF1dGhlbnRpY2F0aW9uIG9jY3VycmVkLFxuICAgICAqL1xuICAgIHB1YmxpYyB2YWxpZGF0ZUF1ZGllbmNlKG9yaWdpbmFsSWRUb2tlbjogRGVjb2RlZElkZW50aXR5VG9rZW4sIG5ld0lkVG9rZW46IERlY29kZWRJZGVudGl0eVRva2VuKSB7XG4gICAgICAgIGlmIChvcmlnaW5hbElkVG9rZW4uYXVkICE9PSBuZXdJZFRva2VuLmF1ZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEF1ZGllbmNlVmFsaWRhdGlvbkVycm9yKHtcbiAgICAgICAgICAgICAgICBvcmlnaW5hbElkVG9rZW4sXG4gICAgICAgICAgICAgICAgbmV3SWRUb2tlblxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBpZiB0aGUgSUQgVG9rZW4gY29udGFpbnMgYW4gYXV0aF90aW1lIENsYWltLCBpdHMgdmFsdWUgTVVTVCByZXByZXNlbnRcbiAgICAgKiB0aGUgdGltZSBvZiB0aGUgb3JpZ2luYWwgYXV0aGVudGljYXRpb24gLSBub3QgdGhlIHRpbWUgdGhhdCB0aGUgbmV3IElEIHRva2VuIGlzIGlzc3VlZCxcbiAgICAgKi9cbiAgICBwdWJsaWMgdmFsaWRhdGVBdXRoVGltZShvcmlnaW5hbElkVG9rZW46IERlY29kZWRJZGVudGl0eVRva2VuLCBuZXdJZFRva2VuOiBEZWNvZGVkSWRlbnRpdHlUb2tlbikge1xuICAgICAgICBpZiAobmV3SWRUb2tlbi5hdXRoX3RpbWUgJiYgKG9yaWdpbmFsSWRUb2tlbi5hdXRoX3RpbWUgIT09IG5ld0lkVG9rZW4uYXV0aF90aW1lKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEF1dGhUaW1lVmFsaWRhdGlvbkVycm9yKHtcbiAgICAgICAgICAgICAgICBvcmlnaW5hbElkVG9rZW4sXG4gICAgICAgICAgICAgICAgbmV3SWRUb2tlblxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBpdHMgYXpwIENsYWltIFZhbHVlIE1VU1QgYmUgdGhlIHNhbWUgYXMgaW4gdGhlIElEIFRva2VuIGlzc3VlZCB3aGVuIHRoZSBvcmlnaW5hbCBhdXRoZW50aWNhdGlvbiBvY2N1cnJlZDtcbiAgICAgKiBpZiBubyBhenAgQ2xhaW0gd2FzIHByZXNlbnQgaW4gdGhlIG9yaWdpbmFsIElEIFRva2VuLCBvbmUgTVVTVCBOT1QgYmUgcHJlc2VudCBpbiB0aGUgbmV3IElEIFRva2VuLCBhbmRcbiAgICAgKiBvdGhlcndpc2UsIHRoZSBzYW1lIHJ1bGVzIGFwcGx5IGFzIGFwcGx5IHdoZW4gaXNzdWluZyBhbiBJRCBUb2tlbiBhdCB0aGUgdGltZSBvZiB0aGUgb3JpZ2luYWwgYXV0aGVudGljYXRpb24uXG4gICAgICovXG4gICAgcHVibGljIHZhbGlkYXRlQXV0aG9yaXplZFBhcnR5KG9yaWdpbmFsSWRUb2tlbjogRGVjb2RlZElkZW50aXR5VG9rZW4sIG5ld0lkVG9rZW46IERlY29kZWRJZGVudGl0eVRva2VuKSB7XG4gICAgICAgIGlmIChvcmlnaW5hbElkVG9rZW4uYXpwICE9PSBuZXdJZFRva2VuLmF6cCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEF1dGhvcml6ZWRQYXJ0eVZhbGlkYXRpb25FcnJvcih7XG4gICAgICAgICAgICAgICAgb3JpZ2luYWxJZFRva2VuLFxuICAgICAgICAgICAgICAgIG5ld0lkVG9rZW5cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuIl19