Merge pull request #6440 from Budibase/fix/couch-db-url-parsing

Improve Couch DB URL parsing to handle edge cases and special characters
This commit is contained in:
Andrew Kingston 2022-06-23 14:59:58 +01:00 committed by GitHub
commit 0f6ad15b14
2 changed files with 97 additions and 14 deletions

View File

@ -1,21 +1,42 @@
const PouchDB = require("pouchdb") const PouchDB = require("pouchdb")
const env = require("../environment") const env = require("../environment")
function getUrlInfo() { exports.getUrlInfo = (url = env.COUCH_DB_URL) => {
let url = env.COUCH_DB_URL let cleanUrl, username, password, host
let username, password, host if (url) {
const [protocol, rest] = url.split("://") // Ensure the URL starts with a protocol
const protoRegex = /^https?:\/\//i
if (!protoRegex.test(url)) {
url = `http://${url}`
}
// Split into protocol and remainder
const split = url.split("://")
const protocol = split[0]
const rest = split.slice(1).join("://")
// Extract auth if specified
if (url.includes("@")) { if (url.includes("@")) {
const hostParts = rest.split("@") // Split into host and remainder
host = hostParts[1] let parts = rest.split("@")
const authParts = hostParts[0].split(":") host = parts[parts.length - 1]
let auth = parts.slice(0, -1).join("@")
// Split auth into username and password
if (auth.includes(":")) {
const authParts = auth.split(":")
username = authParts[0] username = authParts[0]
password = authParts[1] password = authParts.slice(1).join(":")
} else {
username = auth
}
} else { } else {
host = rest host = rest
} }
cleanUrl = `${protocol}://${host}`
}
return { return {
url: `${protocol}://${host}`, url: cleanUrl,
auth: { auth: {
username, username,
password, password,
@ -24,7 +45,7 @@ function getUrlInfo() {
} }
exports.getCouchInfo = () => { exports.getCouchInfo = () => {
const urlInfo = getUrlInfo() const urlInfo = exports.getUrlInfo()
let username let username
let password let password
if (env.COUCH_DB_USERNAME) { if (env.COUCH_DB_USERNAME) {

View File

@ -0,0 +1,62 @@
require("../../../tests/utilities/TestConfiguration")
const getUrlInfo = require("../pouch").getUrlInfo
describe("pouch", () => {
describe("Couch DB URL parsing", () => {
it("should handle a null Couch DB URL", () => {
const info = getUrlInfo(null)
expect(info.url).toBeUndefined()
expect(info.auth.username).toBeUndefined()
})
it("should be able to parse a basic Couch DB URL", () => {
const info = getUrlInfo("http://host.com")
expect(info.url).toBe("http://host.com")
expect(info.auth.username).toBeUndefined()
})
it("should be able to parse a Couch DB basic URL with HTTPS", () => {
const info = getUrlInfo("https://host.com")
expect(info.url).toBe("https://host.com")
expect(info.auth.username).toBeUndefined()
})
it("should be able to parse a basic Couch DB URL with a custom port", () => {
const info = getUrlInfo("https://host.com:1234")
expect(info.url).toBe("https://host.com:1234")
expect(info.auth.username).toBeUndefined()
})
it("should be able to parse a Couch DB URL with auth", () => {
const info = getUrlInfo("https://user:pass@host.com:1234")
expect(info.url).toBe("https://host.com:1234")
expect(info.auth.username).toBe("user")
expect(info.auth.password).toBe("pass")
})
it("should be able to parse a Couch DB URL with auth and special chars", () => {
const info = getUrlInfo("https://user:s:p@s://@://:d@;][~s@host.com:1234")
expect(info.url).toBe("https://host.com:1234")
expect(info.auth.username).toBe("user")
expect(info.auth.password).toBe("s:p@s://@://:d@;][~s")
})
it("should be able to parse a Couch DB URL without a protocol", () => {
const info = getUrlInfo("host.com:1234")
expect(info.url).toBe("http://host.com:1234")
expect(info.auth.username).toBeUndefined()
})
it("should be able to parse a Couch DB URL with auth and without a protocol", () => {
const info = getUrlInfo("user:s:p@s://@://:d@;][~s@host.com:1234")
expect(info.url).toBe("http://host.com:1234")
expect(info.auth.username).toBe("user")
expect(info.auth.password).toBe("s:p@s://@://:d@;][~s")
})
it("should be able to parse a Couch DB URL with only username auth", () => {
const info = getUrlInfo("https://user@host.com:1234")
expect(info.url).toBe("https://host.com:1234")
expect(info.auth.username).toBe("user")
expect(info.auth.password).toBeUndefined()
})
it("should be able to parse a Couch DB URL with only username auth and without a protocol", () => {
const info = getUrlInfo("user@host.com:1234")
expect(info.url).toBe("http://host.com:1234")
expect(info.auth.username).toBe("user")
expect(info.auth.password).toBeUndefined()
})
})
})