1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00
Files
joplin/packages/lib/SyncTargetJoplinServerSAML.ts

135 lines
3.8 KiB
TypeScript

import FileApiDriverJoplinServer from './file-api-driver-joplinServer';
import Setting from './models/Setting';
import { _ } from './locale.js';
import JoplinServerApi, { Session } from './JoplinServerApi';
import { FileApi } from './file-api';
import SyncTargetJoplinServer, { FileApiOptions } from './SyncTargetJoplinServer';
import Logger from '@joplin/utils/Logger';
export async function newFileApi(id: number, options: FileApiOptions) {
const apiOptions = {
baseUrl: () => options.path(),
userContentBaseUrl: () => options.userContentPath(),
username: () => '',
password: () => '',
session: () => ({ id: Setting.value('sync.11.id'), user_id: Setting.value('sync.11.userId') }),
env: Setting.value('env'),
};
const api = new JoplinServerApi(apiOptions);
const driver = new FileApiDriverJoplinServer(api);
const fileApi = new FileApi('', driver);
fileApi.setSyncTargetId(id);
await fileApi.initialize();
return fileApi;
}
export async function initFileApi(syncTargetId: number, logger: Logger, options: FileApiOptions) {
const fileApi = await newFileApi(syncTargetId, options);
fileApi.setLogger(logger);
return fileApi;
}
export const authenticateWithCode = async (code: string) => {
try {
const response = await fetch(`${Setting.value('sync.11.path')}/api/login_with_code/${code}`);
if (response.status !== 200) {
return false;
}
const token: Session = await response.json();
Setting.setValue('sync.11.id', token.id);
Setting.setValue('sync.11.userId', token.user_id);
} catch (_e) {
return false;
}
return true;
};
// A sync target for Joplin Server that uses SAML for authentication.
//
// Based on the regular Joplin Server sync target.
export default class SyncTargetJoplinServerSAML extends SyncTargetJoplinServer {
private lastFileApiOptions_: FileApiOptions|null = null;
public static override id() {
return 11;
}
public static override targetName() {
return 'joplinServerSaml';
}
public static override label() {
return `${_('Joplin Server (SAML)')}`;
}
public override async isAuthenticated() {
if (!Setting.value('sync.11.id')) return false;
// We check that the file API has been initialized at least once, otherwise the below check
// will always fail and it will be impossible to login.
if (this.lastFileApiOptions_) {
const check = await SyncTargetJoplinServer.checkConfig(null, null, await this.fileApi());
return check.ok;
}
return true;
}
public static override requiresPassword() {
return false;
}
public static override async checkConfig(fileApi: FileApiOptions) {
try {
// Simulate a login request
const result = await fetch(`${fileApi.path()}/api/saml`);
if (result.status === 200) { // The server successfully responded, SAML is enabled
return {
ok: true,
errorMessage: '',
};
} else { // SAML is disabled or an error occurred
const text = await result.text();
let message = text; // Use the textual body as the default message
// Check if we got an error message
if (result.headers.get('Content-Type').includes('application/json')) {
try {
const json = JSON.parse(text);
if (json.error) {
message = json.error;
}
} catch (_e) {} // eslint-disable-line no-empty -- Keep the plain text response as the error message, ignore the parsing exception
}
return {
ok: false,
errorMessage: `Could not connect to server: Error ${result.status}: ${message}`,
};
}
} catch (e) {
return {
ok: false,
errorMessage: e.message,
};
}
}
protected override async initFileApi() {
this.lastFileApiOptions_ = {
path: () => Setting.value('sync.11.path'),
userContentPath: () => Setting.value('sync.11.userContentPath'),
username: () => '',
password: () => '',
};
return initFileApi(SyncTargetJoplinServerSAML.id(), this.logger(), this.lastFileApiOptions_);
}
}