Skip to content

Commit

Permalink
Add --insecure flag instead of NODE_TLS_REJECT_UNAUTHORIZED=0
Browse files Browse the repository at this point in the history
  • Loading branch information
mihaeu committed Jun 6, 2022
1 parent a0294da commit ad6b3a4
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 27 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added config option `personalAccessToken` and environment variable `CONFLUENCE_PERSONAL_ACCESS_TOKEN` in order to support authentication using [personal access tokens](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html). (solves [#26](https://github.com/mihaeu/cosmere/issues/26))
- Added `--insecure` flag in order to not have to use `NODE_TLS_REJECT_UNAUTHORIZED=0` in cases where it's needed.

### Changed

- Pictures are now only uploaded if they differ in filename or size. Only pictures that do not match will be deleted remotely (previously all pictures were deleted, then all were uploaded).

### Fixed

- Fixed cache check so that only real changes in files require an update.

## [0.14.1] - 2021-08-25

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ or create an alias:

### Custom certificates on Confluence instance

Prepend `NODE_TLS_REJECT_UNAUTHORIZED=0` to your `cosmere` call in order to not reject invalid certificates. This is risky and it's preferable to get proper certificates.
Use the `--insecure` option for your `cosmere` call in order to not reject invalid certificates. This is risky, and it's preferable to get proper certificates.

## Need new features?

Expand Down
5 changes: 3 additions & 2 deletions bin/cosmere
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
const docopt = require('docopt');
const options = docopt.docopt(`
Usage:
cosmere [--force] [--config=<path>]
cosmere [--force] [--insecure] [--config=<path>]
cosmere generate-config [--config=<path>]
Options:
--force always upload even if the file looks the same
--insecure disables certificate verification (!this makes the transfer insecure!)
--config=<path> specify the path to the config
`);

if (options['generate-config']) {
require('../dist/src/cli/GenerateCommand').default(options['--config']);
} else {
require('../dist/src/cli/MainCommand').default(options['--config'], options['--force'])
require('../dist/src/cli/MainCommand').default(options['--config'], options['--force'], options['--insecure'])
.then()
.catch(e => {
require('signale').fatal(e);
Expand Down
42 changes: 22 additions & 20 deletions src/api/ConfluenceAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,42 @@ import * as fs from "fs";
import signale from "signale";
import { GetAttachmentsResult } from "./GetAttachmentsResult";
import { Attachment } from "./Attachment";
import { Agent } from "https";

export class ConfluenceAPI {
private readonly baseUrl: string;
private readonly authHeader: {
Authorization: string;
};
private readonly agent: Agent;

constructor(baseUrl: string, authorizationToken: string) {
constructor(baseUrl: string, authorizationToken: string, insecure: boolean) {
this.baseUrl = baseUrl;
this.authHeader = {
Authorization: authorizationToken,
};
this.agent = new (require("https").Agent)({
rejectUnauthorized: !insecure,
});
}

async updateConfluencePage(pageId: string, newPage: any) {
const config = {
headers: {
...this.authHeader,
"Content-Type": "application/json",
},
};
try {
await axios.put(`${this.baseUrl}/content/${pageId}`, newPage, config);
await axios.put(`${this.baseUrl}/content/${pageId}`, newPage, this.config());
} catch (e) {
signale.await(`First attempt failed, retrying ...`);
await axios.put(`${this.baseUrl}/content/${pageId}`, newPage, config);
await axios.put(`${this.baseUrl}/content/${pageId}`, newPage, this.config());
}
}

async getAttachments(pageId: string): Promise<GetAttachmentsResult> {
return (
await axios.get(`${this.baseUrl}/content/${pageId}/child/attachment`, {
headers: this.authHeader,
})
).data;
return (await axios.get(`${this.baseUrl}/content/${pageId}/child/attachment`, this.config())).data;
}

async deleteAttachment(attachment: Attachment) {
try {
signale.await(`Deleting attachment "${attachment.title}" ...`);
await axios.delete(`${this.baseUrl}/content/${attachment.id}`, {
headers: this.authHeader,
});
await axios.delete(`${this.baseUrl}/content/${attachment.id}`, this.config());
} catch (e) {
signale.error(`Deleting attachment "${attachment.title}" failed ...`);
}
Expand All @@ -60,6 +53,7 @@ export class ConfluenceAPI {
"X-Atlassian-Token": "nocheck",
...this.authHeader,
},
httpsAgent: this.agent,
data: {
file: fs.createReadStream(filename),
},
Expand All @@ -70,8 +64,16 @@ export class ConfluenceAPI {
}

async currentPage(pageId: string) {
return axios.get(`${this.baseUrl}/content/${pageId}?expand=body.storage,version`, {
headers: this.authHeader,
});
return axios.get(`${this.baseUrl}/content/${pageId}?expand=body.storage,version`, this.config());
}

private config() {
return {
headers: {
...this.authHeader,
"Content-Type": "application/json",
},
httpsAgent: this.agent,
};
}
}
4 changes: 2 additions & 2 deletions src/cli/MainCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { ConfigLoader } from "../ConfigLoader";
import { ConfluenceAPI } from "../api/ConfluenceAPI";
import { updatePage } from "../UpdatePage";

export default async function(configPath: string | null, force: boolean = false) {
export default async function(configPath: string | null, force: boolean = false, insecure: boolean = false) {
const config: Config = await ConfigLoader.load(configPath);
const confluenceAPI = new ConfluenceAPI(config.baseUrl, config.authorizationToken);
const confluenceAPI = new ConfluenceAPI(config.baseUrl, config.authorizationToken, insecure);

for (const pageData of config.pages) {
await updatePage(confluenceAPI, pageData, config, force);
Expand Down
2 changes: 1 addition & 1 deletion tests/UpdatePage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ describe("UpdatePage", () => {
configPath: "...",
authorizationToken: "Bearer unbearable",
};
expect(updatePage(new ConfluenceAPI("", "Bearer unbearable"), pageData, config, false)).toBeFalsy();
expect(updatePage(new ConfluenceAPI("", "Bearer unbearable", false), pageData, config, false)).toBeFalsy();
});
});
5 changes: 4 additions & 1 deletion tests/api/ConfluenceAPI.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ConfluenceAPI } from "../../src/api/ConfluenceAPI";
import axios from "axios";
import { mocked } from "ts-jest/utils";
import { Agent } from "https";

jest.mock("axios");
const axiosMock = mocked(axios, true);
Expand All @@ -9,12 +10,14 @@ describe("ConfluenceAPI", () => {
it("fetches current version of confluence page", async () => {
axiosMock.get.mockResolvedValue({ data: "Test" });

const confluenceAPI = new ConfluenceAPI("", "Bearer unbearable");
const confluenceAPI = new ConfluenceAPI("", "Bearer unbearable", false);
await confluenceAPI.currentPage("2");
expect(axiosMock.get).toHaveBeenCalledWith("/content/2?expand=body.storage,version", {
headers: {
Authorization: "Bearer unbearable",
"Content-Type": "application/json",
},
httpsAgent: expect.any(Agent),
});
});
});

0 comments on commit ad6b3a4

Please sign in to comment.