This repository has been archived on 2024-09-23. You can view files and clone it, but cannot push or open issues or pull requests.
rocketchat-scim/src/endpoints/ScimEndpoint.ts

143 lines
4.4 KiB
TypeScript
Raw Normal View History

2022-02-14 13:03:16 +00:00
import {
HttpStatusCode,
IHttp,
IHttpResponse,
IModify,
IPersistence,
IRead,
} from "@rocket.chat/apps-engine/definition/accessors";
import {
ApiEndpoint,
IApiEndpointInfo,
IApiRequest,
IApiResponse,
} from "@rocket.chat/apps-engine/definition/api";
import { IApp } from "@rocket.chat/apps-engine/definition/IApp";
2022-02-15 13:09:03 +00:00
import { ConflictError } from "../errors/ConflictError";
import { EmptyRequestError } from "../errors/EmptyRequestError";
import { EmptyResponseError } from "../errors/EmptyResponseError";
import { JsonParseError } from "../errors/JsonParseError";
import { SCIMError, SCIMErrorType } from "../scim/Error";
import { handleRcError } from "./common/endpoint";
2022-02-15 12:38:33 +00:00
import { Context } from "./Context";
2022-02-14 13:03:16 +00:00
type ApiEndpointMethod = (
request: IApiRequest,
endpoint: IApiEndpointInfo,
read: IRead,
modify: IModify,
http: IHttp,
persis: IPersistence,
) => Promise<IApiResponse>;
export interface IScimEndpoint {
2022-02-15 12:38:33 +00:00
_get?(ctx: Context): Promise<IApiResponse>;
_post?(ctx: Context): Promise<IApiResponse>;
_put?(ctx: Context): Promise<IApiResponse>;
_delete?(ctx: Context): Promise<IApiResponse>;
2022-02-14 13:03:16 +00:00
}
export abstract class ScimEndpoint extends ApiEndpoint {
public get: ApiEndpointMethod | undefined;
public post: ApiEndpointMethod | undefined;
public put: ApiEndpointMethod | undefined;
public delete: ApiEndpointMethod | undefined;
protected handleError = handleRcError;
2022-02-14 13:03:16 +00:00
constructor(app: IApp) {
super(app);
this.get = this.wrapMethod("get");
this.post = this.wrapMethod("post");
this.put = this.wrapMethod("put");
this.delete = this.wrapMethod("delete");
}
protected success(content?: any): IApiResponse {
return this.response({
status: HttpStatusCode.OK,
content,
});
}
protected response(response: IApiResponse): IApiResponse {
if (response.headers === undefined) {
response.headers = {};
}
response.headers["Content-Type"] = "application/scim+json";
return response;
}
protected error(error: SCIMError): IApiResponse {
return this.response({
status: parseInt(error.status, 10),
content: error,
});
}
protected parseResponse(response: IHttpResponse): any {
if (!response.content) {
throw new EmptyResponseError();
}
let content: any;
try {
content = JSON.parse(response.content);
} catch (e) {
throw new JsonParseError();
}
return content;
}
protected hasContent(request: IApiRequest) {
if (!request.content || Object.keys(request.content).length === 0) {
throw new EmptyRequestError();
}
}
private wrapMethod(name: string): ApiEndpointMethod | undefined {
const method = this[`_${name}`];
if (method === undefined || typeof method !== "function") {
return undefined;
}
return async (
request: IApiRequest,
endpoint: IApiEndpointInfo,
read: IRead,
modify: IModify,
http: IHttp,
persis: IPersistence,
): Promise<IApiResponse> => {
2022-03-21 10:20:39 +00:00
const logger = this.app.getLogger();
2022-02-14 13:03:16 +00:00
try {
2022-02-15 15:16:51 +00:00
const ctx = new Context(
request,
endpoint,
read,
modify,
http,
persis,
2022-03-21 10:20:39 +00:00
logger,
2022-02-14 13:03:16 +00:00
);
2022-03-21 10:20:39 +00:00
logger.debug(
`SCIM Request ${name.toUpperCase()} /${this.path}`,
request.content,
);
const response = await method.bind(this)(ctx);
logger.debug("SCIM Response", response);
return response;
2022-02-14 13:03:16 +00:00
} catch (e) {
let err: SCIMError;
if (e.toSCIMError && typeof e.toSCIMError === "function") {
err = e.toSCIMError();
} else {
err = new SCIMError()
.setStatus(HttpStatusCode.INTERNAL_SERVER_ERROR)
.setScimType(SCIMErrorType.INVALID_VALUE)
.setDetail(e.message);
}
2022-03-21 10:20:39 +00:00
logger.error(e);
2022-02-14 13:03:16 +00:00
return this.error(err);
}
};
}
}