| 33 | const DEFAULT_MAX_SCRAM_ITERATIONS = 100000 |
| 34 | |
| 35 | function startSession(mechanisms, stream, scramMaxIterations = DEFAULT_MAX_SCRAM_ITERATIONS) { |
| 36 | const candidates = ['SCRAM-SHA-256'] |
| 37 | if (stream) candidates.unshift('SCRAM-SHA-256-PLUS') // higher-priority, so placed first |
| 38 | |
| 39 | const mechanism = candidates.find((candidate) => mechanisms.includes(candidate)) |
| 40 | |
| 41 | if (!mechanism) { |
| 42 | throw new Error('SASL: Only mechanism(s) ' + candidates.join(' and ') + ' are supported') |
| 43 | } |
| 44 | |
| 45 | if (mechanism === 'SCRAM-SHA-256-PLUS' && typeof stream.getPeerCertificate !== 'function') { |
| 46 | // this should never happen if we are really talking to a Postgres server |
| 47 | throw new Error('SASL: Mechanism SCRAM-SHA-256-PLUS requires a certificate') |
| 48 | } |
| 49 | |
| 50 | const clientNonce = crypto.randomBytes(18).toString('base64') |
| 51 | const gs2Header = mechanism === 'SCRAM-SHA-256-PLUS' ? 'p=tls-server-end-point' : stream ? 'y' : 'n' |
| 52 | |
| 53 | return { |
| 54 | mechanism, |
| 55 | clientNonce, |
| 56 | response: gs2Header + ',,n=*,r=' + clientNonce, |
| 57 | message: 'SASLInitialResponse', |
| 58 | scramMaxIterations, |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | async function continueSession(session, password, serverData, stream) { |
| 63 | if (session.message !== 'SASLInitialResponse') { |