source: node_modules/pg-connection-string/index.js@ 06ebe74

finki-main main
Last change on this file since 06ebe74 was 62b2964, checked in by Klimentina Efremova <klimentina08642@…>, 2 weeks ago

Project Handcraft Marketplace

  • Property mode set to 100644
File size: 7.3 KB
Line 
1'use strict'
2
3//Parse method copied from https://github.com/brianc/node-postgres
4//Copyright (c) 2010-2014 Brian Carlson (brian.m.carlson@gmail.com)
5//MIT License
6
7//parses a connection string
8function parse(str, options = {}) {
9 //unix socket
10 if (str.charAt(0) === '/') {
11 const config = str.split(' ')
12 return { host: config[0], database: config[1] }
13 }
14
15 // Check for empty host in URL
16
17 const config = Object.create(null)
18 let result
19 let dummyHost = false
20 if (/ |%[^a-f0-9]|%[a-f0-9][^a-f0-9]/i.test(str)) {
21 // Ensure spaces are encoded as %20
22 str = encodeURI(str).replace(/%25(\d\d)/g, '%$1')
23 }
24
25 try {
26 try {
27 result = new URL(str, 'postgres://base')
28 } catch (e) {
29 // The URL is invalid so try again with a dummy host
30 result = new URL(str.replace('@/', '@___DUMMY___/'), 'postgres://base')
31 dummyHost = true
32 }
33 } catch (err) {
34 // Remove the input from the error message to avoid leaking sensitive information
35 err.input && (err.input = '*****REDACTED*****')
36 throw err
37 }
38
39 // We'd like to use Object.fromEntries() here but Node.js 10 does not support it
40 for (const entry of result.searchParams.entries()) {
41 config[entry[0]] = entry[1]
42 }
43
44 config.user = config.user || decodeURIComponent(result.username)
45 config.password = config.password || decodeURIComponent(result.password)
46
47 if (result.protocol == 'socket:') {
48 config.host = decodeURI(result.pathname)
49 config.database = result.searchParams.get('db')
50 config.client_encoding = result.searchParams.get('encoding')
51 return config
52 }
53 const hostname = dummyHost ? '' : result.hostname
54 if (!config.host) {
55 // Only set the host if there is no equivalent query param.
56 config.host = decodeURIComponent(hostname)
57 } else if (hostname && /^%2f/i.test(hostname)) {
58 // Only prepend the hostname to the pathname if it is not a URL encoded Unix socket host.
59 result.pathname = hostname + result.pathname
60 }
61 if (!config.port) {
62 // Only set the port if there is no equivalent query param.
63 config.port = result.port
64 }
65
66 const pathname = result.pathname.slice(1) || null
67 config.database = pathname ? decodeURI(pathname) : null
68
69 if (config.ssl === 'true' || config.ssl === '1') {
70 config.ssl = true
71 }
72
73 if (config.ssl === '0') {
74 config.ssl = false
75 }
76
77 if (config.sslcert || config.sslkey || config.sslrootcert || config.sslmode) {
78 config.ssl = {}
79 }
80
81 // sslnegotiation=direct implies SSL is in use (libpq requires sslmode>=require),
82 // so enable SSL if the connection string did not otherwise configure it.
83 if (config.sslnegotiation === 'direct' && config.ssl === undefined) {
84 config.ssl = true
85 }
86
87 // Only try to load fs if we expect to read from the disk
88 const fs = config.sslcert || config.sslkey || config.sslrootcert ? require('fs') : null
89
90 if (config.sslcert) {
91 config.ssl.cert = fs.readFileSync(config.sslcert).toString()
92 }
93
94 if (config.sslkey) {
95 config.ssl.key = fs.readFileSync(config.sslkey).toString()
96 }
97
98 if (config.sslrootcert) {
99 config.ssl.ca = fs.readFileSync(config.sslrootcert).toString()
100 }
101
102 if (options.useLibpqCompat && config.uselibpqcompat) {
103 throw new Error('Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.')
104 }
105
106 if (config.uselibpqcompat === 'true' || options.useLibpqCompat) {
107 switch (config.sslmode) {
108 case 'disable': {
109 config.ssl = false
110 break
111 }
112 case 'prefer': {
113 config.ssl.rejectUnauthorized = false
114 break
115 }
116 case 'require': {
117 if (config.sslrootcert) {
118 // If a root CA is specified, behavior of `sslmode=require` will be the same as that of `verify-ca`
119 config.ssl.checkServerIdentity = function () {}
120 } else {
121 config.ssl.rejectUnauthorized = false
122 }
123 break
124 }
125 case 'verify-ca': {
126 if (!config.ssl.ca) {
127 throw new Error(
128 'SECURITY WARNING: Using sslmode=verify-ca requires specifying a CA with sslrootcert. If a public CA is used, verify-ca allows connections to a server that somebody else may have registered with the CA, making you vulnerable to Man-in-the-Middle attacks. Either specify a custom CA certificate with sslrootcert parameter or use sslmode=verify-full for proper security.'
129 )
130 }
131 config.ssl.checkServerIdentity = function () {}
132 break
133 }
134 case 'verify-full': {
135 break
136 }
137 }
138 } else {
139 switch (config.sslmode) {
140 case 'disable': {
141 config.ssl = false
142 break
143 }
144 case 'prefer':
145 case 'require':
146 case 'verify-ca':
147 case 'verify-full': {
148 if (config.sslmode !== 'verify-full') {
149 deprecatedSslModeWarning(config.sslmode)
150 }
151 break
152 }
153 case 'no-verify': {
154 config.ssl.rejectUnauthorized = false
155 break
156 }
157 }
158 }
159
160 return config
161}
162
163// convert pg-connection-string ssl config to a ClientConfig.ConnectionOptions
164function toConnectionOptions(sslConfig) {
165 const connectionOptions = Object.entries(sslConfig).reduce((c, [key, value]) => {
166 // we explicitly check for undefined and null instead of `if (value)` because some
167 // options accept falsy values. Example: `ssl.rejectUnauthorized = false`
168 if (value !== undefined && value !== null) {
169 c[key] = value
170 }
171
172 return c
173 }, Object.create(null))
174
175 return connectionOptions
176}
177
178// convert pg-connection-string config to a ClientConfig
179function toClientConfig(config) {
180 const poolConfig = Object.entries(config).reduce((c, [key, value]) => {
181 if (key === 'ssl') {
182 const sslConfig = value
183
184 if (typeof sslConfig === 'boolean') {
185 c[key] = sslConfig
186 }
187
188 if (typeof sslConfig === 'object') {
189 c[key] = toConnectionOptions(sslConfig)
190 }
191 } else if (value !== undefined && value !== null) {
192 if (key === 'port') {
193 // when port is not specified, it is converted into an empty string
194 // we want to avoid NaN or empty string as a values in ClientConfig
195 if (value !== '') {
196 const v = parseInt(value, 10)
197 if (isNaN(v)) {
198 throw new Error(`Invalid ${key}: ${value}`)
199 }
200
201 c[key] = v
202 }
203 } else {
204 c[key] = value
205 }
206 }
207
208 return c
209 }, Object.create(null))
210
211 return poolConfig
212}
213
214// parses a connection string into ClientConfig
215function parseIntoClientConfig(str) {
216 return toClientConfig(parse(str))
217}
218
219function deprecatedSslModeWarning(sslmode) {
220 if (!deprecatedSslModeWarning.warned && typeof process !== 'undefined' && process.emitWarning) {
221 deprecatedSslModeWarning.warned = true
222 process.emitWarning(`SECURITY WARNING: The SSL modes 'prefer', 'require', and 'verify-ca' are treated as aliases for 'verify-full'.
223In the next major version (pg-connection-string v3.0.0 and pg v9.0.0), these modes will adopt standard libpq semantics, which have weaker security guarantees.
224
225To prepare for this change:
226- If you want the current behavior, explicitly use 'sslmode=verify-full'
227- If you want libpq compatibility now, use 'uselibpqcompat=true&sslmode=${sslmode}'
228
229See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode definitions.`)
230 }
231}
232
233module.exports = parse
234
235parse.parse = parse
236parse.toClientConfig = toClientConfig
237parse.parseIntoClientConfig = parseIntoClientConfig
Note: See TracBrowser for help on using the repository browser.