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";
|
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;
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected handleError(o: any) {
|
|
|
|
if (!o.success) {
|
2022-02-15 12:38:33 +00:00
|
|
|
if (o.error?.includes("already in use")) {
|
2022-02-14 13:03:16 +00:00
|
|
|
throw new ConflictError(
|
|
|
|
o.error.includes("@") ? "email" : "username",
|
|
|
|
);
|
|
|
|
}
|
2022-02-15 12:38:33 +00:00
|
|
|
if (o.error?.includes("not found")) {
|
2022-02-14 13:03:16 +00:00
|
|
|
}
|
|
|
|
throw new Error(o.error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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> => {
|
|
|
|
try {
|
|
|
|
return await method.bind(this)(
|
2022-02-15 12:38:33 +00:00
|
|
|
new Context(request, endpoint, read, modify, http, persis),
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.error(err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|