Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 70 additions & 127 deletions endpoints/AuthenticationEndpoint.ts
Original file line number Diff line number Diff line change
@@ -1,156 +1,99 @@
import {
HttpStatusCode,
IHttp,
IModify,
IPersistence,
IRead,
HttpStatusCode,
IHttp,
IModify,
IPersistence,
IRead,
} from "@rocket.chat/apps-engine/definition/accessors";
import {
ApiEndpoint,
IApiEndpointInfo,
IApiRequest,
IApiResponse,
ApiEndpoint,
IApiEndpointInfo,
IApiRequest,
IApiResponse,
} from "@rocket.chat/apps-engine/definition/api";
import { IApiResponseJSON } from "@rocket.chat/apps-engine/definition/api/IResponse";
import { IApp } from "@rocket.chat/apps-engine/definition/IApp";
import { AppSetting } from "../config/Settings";
import {
AuthenticationEndpointPath,
SubscriberEndpointPath,
AuthenticationEndpointPath,
SubscriberEndpointPath,
} from "../lib/Const";
import {
getUserAccessTokenAsync,
getUserProfileAsync,
listSubscriptionsAsync,
subscribeToAllMessagesForOneUserAsync,
getUserAccessTokenAsync,
getUserProfileAsync,
listSubscriptionsAsync,
subscribeToAllMessagesForOneUserAsync,
} from "../lib/MicrosoftGraphApi";
import {
persistUserAccessTokenAsync,
persistUserAsync,
saveLoginMessageSentStatus,
persistUserAccessTokenAsync,
persistUserAsync,
saveLoginMessageSentStatus,
} from "../lib/PersistHelper";
import { getRocketChatAppEndpointUrl } from "../lib/UrlHelper";

export class AuthenticationEndpoint extends ApiEndpoint {
private embeddedLoginSuccessMessage: string =
"Login to Teams succeed! You can close this window now.";
private embeddedLoginFailureMessage: string =
"Login to Teams failed! Please check document or contact your organization admin.";
private embeddedLoginSuccessMessage = "Login to Teams succeed! You can close this window now.";
private embeddedLoginFailureMessage = "Login to Teams failed! Please check the documentation or contact your organization admin.";

public path = AuthenticationEndpointPath;
public path = AuthenticationEndpointPath;

constructor(app: IApp) {
super(app);
this.errorResponse = this.errorResponse.bind(this);
}

public async get(
request: IApiRequest,
endpoint: IApiEndpointInfo,
read: IRead,
modify: IModify,
http: IHttp,
persis: IPersistence
): Promise<IApiResponse> {
if (request.query.error && !request.query.code) {
return this.errorResponse();
}
constructor(app: IApp) {
super(app);
this.errorResponse = this.errorResponse.bind(this);
}

try {
const aadTenantId = (
await read
.getEnvironmentReader()
.getSettings()
.getById(AppSetting.AadTenantId)
).value;
const aadClientId = (
await read
.getEnvironmentReader()
.getSettings()
.getById(AppSetting.AadClientId)
).value;
const aadClientSecret = (
await read
.getEnvironmentReader()
.getSettings()
.getById(AppSetting.AadClientSecret)
).value;
public async get(
request: IApiRequest,
endpoint: IApiEndpointInfo,
read: IRead,
modify: IModify,
http: IHttp,
persist: IPersistence
): Promise<IApiResponse> {
if (request.query.error && !request.query.code) {
return this.errorResponse();
}

const rocketChatUserId: string = request.query.state;
const accessCode: string = request.query.code;
const authEndpointUrl = await getRocketChatAppEndpointUrl(
this.app.getAccessors(),
AuthenticationEndpointPath
);
try {
const aadTenantId = await this.getAppSetting(read, AppSetting.AadTenantId);
const aadClientId = await this.getAppSetting(read, AppSetting.AadClientId);
const aadClientSecret = await this.getAppSetting(read, AppSetting.AadClientSecret);

const response = await getUserAccessTokenAsync(
http,
accessCode,
authEndpointUrl,
aadTenantId,
aadClientId,
aadClientSecret
);
const rocketChatUserId = request.query.state;
const accessCode = request.query.code;
const authEndpointUrl = await getRocketChatAppEndpointUrl(this.app.getAccessors(), AuthenticationEndpointPath);

const userAccessToken = response.accessToken;
const response = await getUserAccessTokenAsync(
http,
accessCode,
authEndpointUrl,
aadTenantId,
aadClientId,
aadClientSecret
);

const teamsUserProfile = await getUserProfileAsync(
http,
userAccessToken
);
const { accessToken: userAccessToken, refreshToken, expiresIn, extExpiresIn } = response;

await Promise.all([
persistUserAccessTokenAsync(
persis,
rocketChatUserId,
userAccessToken,
response.refreshToken as string,
response.expiresIn,
response.extExpiresIn
),
persistUserAsync(persis, rocketChatUserId, teamsUserProfile.id),
saveLoginMessageSentStatus({
persistence: persis,
rocketChatUserId,
wasSent: false,
}),
]);
const teamsUserProfile = await getUserProfileAsync(http, userAccessToken);

// Only create subscription if there's no existing one to prevent error
const subscriptions = await listSubscriptionsAsync(
http,
userAccessToken
);
if (!subscriptions || subscriptions.length == 0) {
const subscriberEndpointUrl = await getRocketChatAppEndpointUrl(
this.app.getAccessors(),
SubscriberEndpointPath
);
await Promise.all([
persistUserAccessTokenAsync(persist, rocketChatUserId, userAccessToken, refreshToken as string, expiresIn, extExpiresIn),
persistUserAsync(persist, rocketChatUserId, teamsUserProfile.id),
saveLoginMessageSentStatus({ persistence: persist, rocketChatUserId, wasSent: false }),
]);

// Async operation to create subscription
subscribeToAllMessagesForOneUserAsync(
http,
rocketChatUserId,
teamsUserProfile.id,
subscriberEndpointUrl,
userAccessToken
);
}
const subscriptions = await listSubscriptionsAsync(http, userAccessToken);
if (!subscriptions || subscriptions.length === 0) {
const subscriberEndpointUrl = await getRocketChatAppEndpointUrl(this.app.getAccessors(), SubscriberEndpointPath);
subscribeToAllMessagesForOneUserAsync(http, rocketChatUserId, teamsUserProfile.id, subscriberEndpointUrl, userAccessToken);
}

return this.success(this.embeddedLoginSuccessMessage);
} catch (error) {
return this.errorResponse();
}
return this.success(this.embeddedLoginSuccessMessage);
} catch (error) {
return this.errorResponse();
}
}

private errorResponse(): IApiResponse {
const response: IApiResponseJSON = {
status: HttpStatusCode.BAD_REQUEST,
content: {
message: this.embeddedLoginFailureMessage,
},
};

return response;
}
}
private async getAppSetting(read: IRead, settingId: AppSetting): Promise<string> {
const setting = await read.getEnvironmentReader().getSettings().getById(settingId);