Skip to content

Commit

Permalink
Added X-OnlyAuthenticated-Header (#28)
Browse files Browse the repository at this point in the history
* Added X-OnlyAuthenticated-Header

* fixed prettier

---------

Co-authored-by: sguenter <sguenther@churchtools.de>
  • Loading branch information
Ainias and sguenter authored Mar 12, 2024
1 parent ec51853 commit b166729
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 13 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
/.idea
/dist
/dist

.env
86 changes: 74 additions & 12 deletions src/churchtoolsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ export type PageResponse<Result> = {

type Resolver<Result> = (result: Result | PromiseLike<Result>) => void;

type GetOptions = { rawResponse?: boolean; callDeferred?: boolean; enforceJSON?: boolean };
type PutOptions = { enforceJSON?: boolean };
type PostOptions = { enforceJSON?: boolean, abortController?: AbortController };
type DeleteOptions = { enforceJSON?: boolean };
type PatchOptions = { enforceJSON?: boolean };
type RequestOptions = { enforceJSON?: boolean; needsAuthentication?: boolean };

type GetOptions = RequestOptions & { rawResponse?: boolean; callDeferred?: boolean };
type PutOptions = RequestOptions;
type PostOptions = RequestOptions & { abortController?: AbortController };
type DeleteOptions = RequestOptions;
type PatchOptions = RequestOptions;

type Rejecter = (error: any) => void;

Expand All @@ -59,6 +61,9 @@ class ChurchToolsClient {
private rateLimitTimeout = RATE_LIMIT_TIMEOUT;
private currentLoginPromise?: Promise<any>;

private needsAuthentication: boolean | undefined;
private hasToken = false;

private enforceJSON = false;

public ChurchToolsClient = ChurchToolsClient;
Expand All @@ -78,9 +83,25 @@ class ChurchToolsClient {
return response;
}, logError);

// Set headers for authentication
this.ax.interceptors.request.use((config) => {
// The backend only checks if the header is set. So if the header is set to false, remove it
if (config.headers?.['X-OnlyAuthenticated'] === '0') {
delete config.headers['X-OnlyAuthenticated'];
} else if (!config.headers?.['X-OnlyAuthenticated'] && (this.needsAuthentication ?? this.hasToken)) {
config.headers = config.headers ?? {};
config.headers['X-OnlyAuthenticated'] = '1';
}
return config;
});

this.setUnauthorizedInterceptor(loginToken);
}

setNeedsAuthentication(needsAuthentication: boolean) {
this.needsAuthentication = needsAuthentication;
}

/**
* Sets the default ChurchTools url.
*
Expand Down Expand Up @@ -191,7 +212,7 @@ class ChurchToolsClient {
headers: {
'CSRF-Token': this.csrfToken ?? '',
},
signal: this.getAbortSignal()
signal: this.getAbortSignal(),
}
);
})
Expand Down Expand Up @@ -242,7 +263,7 @@ class ChurchToolsClient {
rawResponse?: boolean,
callDeferred?: boolean
): Promise<ResponseType>;
get<ResponseType>(uri: string, params: Params, options: GetOptions): Promise<ResponseType>;
get<ResponseType>(uri: string, params?: Params, options?: GetOptions): Promise<ResponseType>;
get<ResponseType>(
uri: string,
params = {},
Expand All @@ -254,12 +275,20 @@ class ChurchToolsClient {
callDeferred =
typeof rawResponseOrOptions === 'object' ? rawResponseOrOptions.callDeferred ?? true : callDeferred;
const enforceJson = typeof rawResponseOrOptions === 'object' ? rawResponseOrOptions.enforceJSON : undefined;
const needsAuthentication =
typeof rawResponseOrOptions === 'object' ? rawResponseOrOptions.needsAuthentication : undefined;

const headers: Record<string, any> = {};
if (needsAuthentication !== undefined) {
headers['X-OnlyAuthenticated'] = needsAuthentication ? '1' : '0';
}

const cb = (resolve: Resolver<ResponseType>, reject: Rejecter) =>
this.ax
.get(this.buildUrl(uri), {
params: { ...params, [ENFORCE_JSON_PARAM]: enforceJson },
signal: this.getAbortSignal()
signal: this.getAbortSignal(),
headers,
})
.then((response) => {
if (rawResponse) {
Expand Down Expand Up @@ -312,6 +341,13 @@ class ChurchToolsClient {

put<ResponseType>(uri: string, data: Params, options: PutOptions = {}) {
return new Promise<ResponseType>((resolve, reject) => {
const needsAuthentication = options.needsAuthentication;

const headers: Record<string, any> = {};
if (needsAuthentication !== undefined) {
headers['X-OnlyAuthenticated'] = needsAuthentication ? '1' : '0';
}

this.deferredExecution(() =>
this.ax
.put(
Expand All @@ -320,7 +356,7 @@ class ChurchToolsClient {
...data,
[ENFORCE_JSON_PARAM]: options?.enforceJSON,
},
{ signal: this.getAbortSignal() }
{ signal: this.getAbortSignal(), headers }
)
.then((response) => {
resolve(this.responseToData(response));
Expand All @@ -338,6 +374,13 @@ class ChurchToolsClient {
const needsCsrfToken =
(!globalThis.FormData && data && data.constructor && data.constructor.name === 'FormData') || // Node-JS
(globalThis.FormData && data instanceof FormData); // browser/react-native
const needsAuthentication = options.needsAuthentication;

const headers: Record<string, any> = {};
if (needsAuthentication !== undefined) {
headers['X-OnlyAuthenticated'] = needsAuthentication ? '1' : '0';
}

return new Promise<ResponseType>((resolve, reject) => {
this.deferredExecution(() =>
Promise.resolve()
Expand All @@ -352,9 +395,12 @@ class ChurchToolsClient {
});
})
.then(() => {
const config: AxiosRequestConfig<Params> = {};
const config: AxiosRequestConfig<Params> = {
headers,
};
if (needsCsrfToken) {
config.headers = {
...config.headers,
'CSRF-Token': this.csrfToken ?? '',
};
}
Expand Down Expand Up @@ -382,6 +428,13 @@ class ChurchToolsClient {
}

patch<ResponseType>(uri: string, data: Params = {}, options: PatchOptions = {}) {
const needsAuthentication = options.needsAuthentication;

const headers: Record<string, any> = {};
if (needsAuthentication !== undefined) {
headers['X-OnlyAuthenticated'] = needsAuthentication ? '1' : '0';
}

return new Promise<ResponseType>((resolve, reject) => {
this.deferredExecution(() =>
this.ax
Expand All @@ -391,7 +444,7 @@ class ChurchToolsClient {
...data,
[ENFORCE_JSON_PARAM]: options?.enforceJSON,
},
{ signal: this.getAbortSignal() }
{ signal: this.getAbortSignal(), headers }
)
.then((response) => {
resolve(this.responseToData(response));
Expand All @@ -404,12 +457,20 @@ class ChurchToolsClient {
}

deleteApi<ResponseType>(uri: string, data: Params = {}, options: DeleteOptions = {}) {
const needsAuthentication = options.needsAuthentication;

const headers: Record<string, any> = {};
if (needsAuthentication !== undefined) {
headers['X-OnlyAuthenticated'] = needsAuthentication ? '1' : '0';
}

return new Promise<ResponseType>((resolve, reject) => {
this.deferredExecution(() =>
this.ax
.delete(this.buildUrl(uri), {
data: { ...data, [ENFORCE_JSON_PARAM]: options?.enforceJSON },
signal: this.getAbortSignal()
signal: this.getAbortSignal(),
headers,
})
.then((response) => {
resolve(this.responseToData(response));
Expand Down Expand Up @@ -560,6 +621,7 @@ class ChurchToolsClient {
},
(errorObject) => handleUnauthorized(errorObject.response, errorObject)
);
this.hasToken = !!loginToken;
}

onUnauthenticated(callback: () => void) {
Expand Down

0 comments on commit b166729

Please sign in to comment.