diff --git a/lib/DefaultOptions.ts b/lib/DefaultOptions.ts index 596db49..5c7039e 100644 --- a/lib/DefaultOptions.ts +++ b/lib/DefaultOptions.ts @@ -15,17 +15,25 @@ export class DefaultOptions extends Options { name: 'user', flag: 'u', description: 'Username for checking all confluence documents', - required: true, + required: false, }) - confluenceUser: string + confluenceUser: string = '' @option({ name: 'password', flag: 'p', description: 'Password for the user', - required: true, + required: false, + }) + confluencePassword: string = '' + + @option({ + name: 'token', + flag: 't', + description: 'Personal Access Token for the user. If set user and password will be ignored', + required: false, }) - confluencePassword: string + confluencePersonalAccessToken: string = '' @option({ description: 'Log-Level to use (trace, debug, verbose, info, warn, error)', diff --git a/lib/api/Configuration.ts b/lib/api/Configuration.ts index 8eb4665..99242b2 100644 --- a/lib/api/Configuration.ts +++ b/lib/api/Configuration.ts @@ -34,6 +34,11 @@ export class Configuration { */ public confluencePassword: string + /** + * The personal access token of the Confluence user + */ + public confluencePersonalAccessToken: string + /** * The document id of the configuration document */ @@ -94,10 +99,11 @@ export class Configuration { */ private _log: Logger - constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string, configurationDocumentId: string) { + constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string, confluencePersonalAccessToken: string, configurationDocumentId: string) { this.confluenceUrl = confluenceUrl this.confluenceUser = confluenceUser this.confluencePassword = confluencePassword + this.confluencePersonalAccessToken = confluencePersonalAccessToken this.configurationDocumentId = configurationDocumentId this._loaded = false @@ -134,11 +140,20 @@ export class Configuration { // eslint-disable-next-line @typescript-eslint/no-explicit-any let configurationDocument: any try { - configurationDocument = await got(configurationUrl, { - username: this.confluenceUser, - password: this.confluencePassword, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }).json() + if (this.confluencePersonalAccessToken !== '') { + configurationDocument = await got(configurationUrl, { + headers: { + 'Authorization': 'Bearer ' + this.confluencePersonalAccessToken + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }).json() + } else { + configurationDocument = await got(configurationUrl, { + username: this.confluenceUser, + password: this.confluencePassword, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }).json() + } } catch (e) { this._log.error(`Can't fetch configuration document: (${e.name}) ${e.message}`) throw e diff --git a/lib/api/Confluence.ts b/lib/api/Confluence.ts index 4670db8..fe30917 100644 --- a/lib/api/Confluence.ts +++ b/lib/api/Confluence.ts @@ -17,12 +17,14 @@ export class Confluence { public confluenceUrl: string public confluenceUser: string public confluencePassword: string + public confluencePersonalAccessToken: string private _log: Logger - constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string) { + constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string, confluencePersonalAccessToken: string,) { this.confluenceUrl = confluenceUrl this.confluenceUser = confluenceUser this.confluencePassword = confluencePassword + this.confluencePersonalAccessToken = confluencePersonalAccessToken this._log = log.getLogger('Confluence') } @@ -47,11 +49,20 @@ export class Confluence { this._log.debug(`Searching for documents with ${cql}`) do { const configurationUrl = `${this.confluenceUrl}/rest/api/content/search?cql=${cql}&start=${start}&limit=${limit}` - results = await got(configurationUrl, { - username: this.confluenceUser, - password: this.confluencePassword, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }).json() + if (this.confluencePersonalAccessToken !== '') { + results = await got(configurationUrl, { + headers: { + 'Authorization': 'Bearer ' + this.confluencePersonalAccessToken + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }).json() + } else { + results = await got(configurationUrl, { + username: this.confluenceUser, + password: this.confluencePassword, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }).json() + } for (const result of results.results) { documentInfos.push(await this.getDocumentInfo(result.id)) } @@ -69,12 +80,20 @@ export class Confluence { public async getDocumentInfo(documentId: number): Promise { this._log.debug(`Getting document information of document ${documentId}`) const documentUrl = `${this.confluenceUrl}/rest/api/content/${documentId}?expand=ancestors,version,metadata.labels,history` - const document = await got(documentUrl, { - username: this.confluenceUser, - password: this.confluencePassword, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }).json() - + if (this.confluencePersonalAccessToken !== '') { + const document = await got(documentUrl, { + headers: { + 'Authorization': 'Bearer ' + this.confluencePersonalAccessToken + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }).json() + } else { + const document = await got(documentUrl, { + username: this.confluenceUser, + password: this.confluencePassword, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }).json() + } const author = document.version.by.username ?? null const creator = document.history['createdBy'].username ?? null @@ -142,31 +161,61 @@ export class Confluence { public async createConfigurationDocument(space: string, title: string, parentId: string): Promise { const template = await fs.promises.readFile(path.join(__dirname, '..', '..', 'resources', 'configurationDocument.html'), 'utf-8') - const response = await got - .post(`${this.confluenceUrl}/rest/api/content`, { - json: { - type: 'page', - title: title, - space: { - key: space, + let response: any + if (this.confluencePersonalAccessToken !== '') { + response = await got + .post(`${this.confluenceUrl}/rest/api/content`, { + json: { + type: 'page', + title: title, + space: { + key: space, + }, + ancestors: [ + { + id: parentId, + }, + ], + body: { + storage: { + value: template, + representation: 'storage', + }, + }, }, - ancestors: [ - { - id: parentId, + headers: { + 'Authorization': 'Bearer ' + this.confluencePersonalAccessToken + } + }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .json() + } else { + response = await got + .post(`${this.confluenceUrl}/rest/api/content`, { + json: { + type: 'page', + title: title, + space: { + key: space, }, - ], - body: { - storage: { - value: template, - representation: 'storage', + ancestors: [ + { + id: parentId, + }, + ], + body: { + storage: { + value: template, + representation: 'storage', + }, }, }, - }, - username: this.confluenceUser, - password: this.confluencePassword, - }) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .json() + username: this.confluenceUser, + password: this.confluencePassword, + }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .json() + } return response.id } } diff --git a/lib/commands/Check.ts b/lib/commands/Check.ts index 23b4c46..9f94991 100644 --- a/lib/commands/Check.ts +++ b/lib/commands/Check.ts @@ -38,17 +38,29 @@ export default class extends Command { public async execute(options: CheckOptions): Promise { const log = options.getLogger() + if( + options.confluencePersonalAccessToken === '' + && ( + options.confluenceUser === '' + || options.confluencePassword === '' + ) + ) { + log.error('user and/or password parameter not set or empty! When not using the token parameter both of these have to be set!') + return + } + log.info('Checking for outdated documents') const configuration = new Configuration( options.confluenceUrl, options.confluenceUser, options.confluencePassword, + options.confluencePersonalAccessToken, options.configurationDocumentId ) await configuration.load() - const confluence = new Confluence(options.confluenceUrl, options.confluenceUser, options.confluencePassword) + const confluence = new Confluence(options.confluenceUrl, options.confluenceUser, options.confluencePassword, options.confluencePersonalAccessToken) const notification = new Notification(configuration, options.smtpTransportUrl, confluence, null, options.dryRun) diff --git a/lib/commands/CreateConfigurationDocument.ts b/lib/commands/CreateConfigurationDocument.ts index 44b6e3a..f16464c 100644 --- a/lib/commands/CreateConfigurationDocument.ts +++ b/lib/commands/CreateConfigurationDocument.ts @@ -36,9 +36,20 @@ export default class extends Command { public async execute(options: CheckOptions): Promise { const log = options.getLogger() + if( + options.confluencePersonalAccessToken === '' + && ( + options.confluenceUser === '' + || options.confluencePassword === '' + ) + ) { + log.error('user and/or password parameter not set or empty! When not using the token parameter both of these have to be set!') + return + } + log.info('Checking for outdated documents') - const confluence = new Confluence(options.confluenceUrl, options.confluenceUser, options.confluencePassword) + const confluence = new Confluence(options.confluenceUrl, options.confluenceUser, options.confluencePassword, options.confluencePersonalAccessToken) const pageId = await confluence.createConfigurationDocument(options.space, options.title, options.parentId)