Merge pull request #889 from vector-im/login_with_access_token

Add abiity to setup session immediately after registration without using /login
This commit is contained in:
Bruno Windels 2022-10-14 08:54:52 +00:00 committed by GitHub
commit 4d5f202d94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 34 deletions

View File

@ -137,7 +137,7 @@ export class Client {
async startRegistration(homeserver, username, password, initialDeviceDisplayName, flowSelector) { async startRegistration(homeserver, username, password, initialDeviceDisplayName, flowSelector) {
const request = this._platform.request; const request = this._platform.request;
const hsApi = new HomeServerApi({homeserver, request}); const hsApi = new HomeServerApi({homeserver, request});
const registration = new Registration(hsApi, { const registration = new Registration(homeserver, hsApi, {
username, username,
password, password,
initialDeviceDisplayName, initialDeviceDisplayName,
@ -146,6 +146,16 @@ export class Client {
return registration; return registration;
} }
/** Method to start client after registration or with given access token.
* To start the client after registering, use `startWithAuthData(registration.authData)`.
* `homeserver` won't be resolved or normalized using this method,
* use `lookupHomeserver` first if needed (not needed after registration) */
async startWithAuthData({accessToken, deviceId, userId, homeserver}) {
this._platform.logger.run("startWithAuthData", async (log) => {
await this._createSessionAfterAuth({accessToken, deviceId, userId, homeserver}, true, log);
});
}
async startWithLogin(loginMethod, {inspectAccountSetup} = {}) { async startWithLogin(loginMethod, {inspectAccountSetup} = {}) {
const currentStatus = this._status.get(); const currentStatus = this._status.get();
if (currentStatus !== LoadStatus.LoginFailed && if (currentStatus !== LoadStatus.LoginFailed &&
@ -156,23 +166,17 @@ export class Client {
this._resetStatus(); this._resetStatus();
await this._platform.logger.run("login", async log => { await this._platform.logger.run("login", async log => {
this._status.set(LoadStatus.Login); this._status.set(LoadStatus.Login);
const clock = this._platform.clock;
let sessionInfo; let sessionInfo;
try { try {
const request = this._platform.request; const request = this._platform.request;
const hsApi = new HomeServerApi({homeserver: loginMethod.homeserver, request}); const hsApi = new HomeServerApi({homeserver: loginMethod.homeserver, request});
const loginData = await loginMethod.login(hsApi, "Hydrogen", log); const loginData = await loginMethod.login(hsApi, "Hydrogen", log);
const sessionId = this.createNewSessionId();
sessionInfo = { sessionInfo = {
id: sessionId,
deviceId: loginData.device_id, deviceId: loginData.device_id,
userId: loginData.user_id, userId: loginData.user_id,
homeServer: loginMethod.homeserver, // deprecate this over time
homeserver: loginMethod.homeserver, homeserver: loginMethod.homeserver,
accessToken: loginData.access_token, accessToken: loginData.access_token,
lastUsed: clock.now()
}; };
log.set("id", sessionId);
} catch (err) { } catch (err) {
this._error = err; this._error = err;
if (err.name === "HomeServerError") { if (err.name === "HomeServerError") {
@ -191,6 +195,22 @@ export class Client {
} }
return; return;
} }
await this._createSessionAfterAuth(sessionInfo, inspectAccountSetup, log);
});
}
async _createSessionAfterAuth({deviceId, userId, accessToken, homeserver}, inspectAccountSetup, log) {
const id = this.createNewSessionId();
const lastUsed = this._platform.clock.now();
const sessionInfo = {
id,
deviceId,
userId,
homeServer: homeserver, // deprecate this over time
homeserver,
accessToken,
lastUsed,
};
let dehydratedDevice; let dehydratedDevice;
if (inspectAccountSetup) { if (inspectAccountSetup) {
dehydratedDevice = await this._inspectAccountAfterLogin(sessionInfo, log); dehydratedDevice = await this._inspectAccountAfterLogin(sessionInfo, log);
@ -212,7 +232,6 @@ export class Client {
this._error = err; this._error = err;
this._status.set(LoadStatus.Error); this._status.set(LoadStatus.Error);
} }
});
} }
async _loadSessionInfo(sessionInfo, dehydratedDevice, log) { async _loadSessionInfo(sessionInfo, dehydratedDevice, log) {

View File

@ -164,7 +164,7 @@ export class HomeServerApi {
return this._unauthedRequest("GET", this._url("/login")); return this._unauthedRequest("GET", this._url("/login"));
} }
register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record<string, any>, inhibitLogin: boolean = true , options: BaseRequestOptions = {}): IHomeServerRequest { register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record<string, any>, inhibitLogin: boolean = false , options: BaseRequestOptions = {}): IHomeServerRequest {
options.allowedStatusCodes = [401]; options.allowedStatusCodes = [401];
const body: any = { const body: any = {
auth, auth,

View File

@ -25,6 +25,7 @@ import type {
RegistrationResponseMoreDataNeeded, RegistrationResponseMoreDataNeeded,
RegistrationResponse, RegistrationResponse,
RegistrationResponseSuccess, RegistrationResponseSuccess,
AuthData,
RegistrationParams, RegistrationParams,
} from "./types"; } from "./types";
@ -34,9 +35,11 @@ export class Registration {
private readonly _hsApi: HomeServerApi; private readonly _hsApi: HomeServerApi;
private readonly _accountDetails: AccountDetails; private readonly _accountDetails: AccountDetails;
private readonly _flowSelector: FlowSelector; private readonly _flowSelector: FlowSelector;
private _sessionInfo?: RegistrationResponseSuccess private _registerResponse?: RegistrationResponseSuccess;
public readonly homeserver: string;
constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, flowSelector?: FlowSelector) { constructor(homeserver: string, hsApi: HomeServerApi, accountDetails: AccountDetails, flowSelector?: FlowSelector) {
this.homeserver = homeserver;
this._hsApi = hsApi; this._hsApi = hsApi;
this._accountDetails = accountDetails; this._accountDetails = accountDetails;
this._flowSelector = flowSelector ?? (flows => flows[0]); this._flowSelector = flowSelector ?? (flows => flows[0]);
@ -91,7 +94,7 @@ export class Registration {
private async parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) { private async parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) {
switch (response.status) { switch (response.status) {
case 200: case 200:
this._sessionInfo = response; this._registerResponse = response;
return undefined; return undefined;
case 401: case 401:
if (response.completed?.includes(currentStage.type)) { if (response.completed?.includes(currentStage.type)) {
@ -117,7 +120,14 @@ export class Registration {
} }
} }
get sessionInfo(): RegistrationResponseSuccess | undefined { get authData(): AuthData | undefined {
return this._sessionInfo; if (this._registerResponse) {
return {
accessToken: this._registerResponse.access_token,
homeserver: this.homeserver,
userId: this._registerResponse.user_id,
deviceId: this._registerResponse.device_id,
};
}
} }
} }

View File

@ -38,6 +38,13 @@ export type RegistrationResponseSuccess = {
status: 200; status: 200;
} }
export type AuthData = {
userId: string;
deviceId: string;
homeserver: string;
accessToken?: string;
}
export type RegistrationFlow = { export type RegistrationFlow = {
stages: string[]; stages: string[];
} }