( cryptoMethod: CryptoMethod, response: Document, authContext: AuthContext )
| 114 | } |
| 115 | |
| 116 | async function continueScramConversation( |
| 117 | cryptoMethod: CryptoMethod, |
| 118 | response: Document, |
| 119 | authContext: AuthContext |
| 120 | ): Promise<void> { |
| 121 | const connection = authContext.connection; |
| 122 | const credentials = authContext.credentials; |
| 123 | if (!credentials) { |
| 124 | throw new MongoMissingCredentialsError('AuthContext must provide credentials.'); |
| 125 | } |
| 126 | if (!authContext.nonce) { |
| 127 | throw new MongoInvalidArgumentError('Unable to continue SCRAM without valid nonce'); |
| 128 | } |
| 129 | const nonce = authContext.nonce; |
| 130 | |
| 131 | const db = credentials.source; |
| 132 | const username = cleanUsername(credentials.username); |
| 133 | const password = credentials.password; |
| 134 | |
| 135 | const processedPassword = |
| 136 | cryptoMethod === 'sha256' ? saslprep(password) : passwordDigest(username, password); |
| 137 | |
| 138 | const payload: Binary = ByteUtils.isUint8Array(response.payload) |
| 139 | ? new Binary(response.payload) |
| 140 | : response.payload; |
| 141 | |
| 142 | const dict = parsePayload(payload); |
| 143 | |
| 144 | const iterations = parseInt(dict.i, 10); |
| 145 | if (iterations && iterations < 4096) { |
| 146 | // TODO(NODE-3483) |
| 147 | throw new MongoRuntimeError(`Server returned an invalid iteration count ${iterations}`); |
| 148 | } |
| 149 | |
| 150 | const salt = dict.s; |
| 151 | const rnonce = dict.r; |
| 152 | if (rnonce.startsWith('nonce')) { |
| 153 | // TODO(NODE-3483) |
| 154 | throw new MongoRuntimeError(`Server returned an invalid nonce: ${rnonce}`); |
| 155 | } |
| 156 | |
| 157 | // Set up start of proof |
| 158 | const withoutProof = `c=biws,r=${rnonce}`; |
| 159 | const saltedPassword = await HI( |
| 160 | processedPassword, |
| 161 | ByteUtils.fromBase64(salt), |
| 162 | iterations, |
| 163 | cryptoMethod |
| 164 | ); |
| 165 | |
| 166 | const clientKey = await HMAC(cryptoMethod, saltedPassword, 'Client Key'); |
| 167 | const serverKey = await HMAC(cryptoMethod, saltedPassword, 'Server Key'); |
| 168 | const storedKey = await H(cryptoMethod, clientKey); |
| 169 | const firstMessageBytes = clientFirstMessageBare(username, nonce); |
| 170 | const firstMessage = ByteUtils.toUTF8(firstMessageBytes, 0, firstMessageBytes.length, false); |
| 171 | const payloadString = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false); |
| 172 | const authMessage = [firstMessage, payloadString, withoutProof].join(','); |
| 173 |
no test coverage detected