Bug #97664 Connector Node.js rejects URI includes password with certain special characters
Submitted: 16 Nov 2019 4:30 Modified: 18 Jan 2020 10:37
Reporter: Mitani Satoshi (OCA) Email Updates:
Status: Not a Bug Impact on me:
None 
Category:Connector for Node.js Severity:S3 (Non-critical)
Version:8.0.18 OS:Any
Assigned to: Rui Quelhas CPU Architecture:Any

[16 Nov 2019 4:30] Mitani Satoshi
Description:
Node.js connector rejects URI includes password with certain special characters.
I have confirmed that #(hash), <(lt), >(gt), |(pipe), ^(hat), `(backquote) are rejected.

$ node bug.js
Error: Invalid userinfo segment
    at parse (/home/*/node_modules/@mysql/xdevapi/lib/DevAPI/Util/URIParser/parseUserInfo.js:59:15)
    at parse (/home/*/node_modules/@mysql/xdevapi/lib/DevAPI/Util/URIParser/index.js:67:22)
    at parseConnectionSpec (/home/*/node_modules/@mysql/xdevapi/index.js:80:20)
    at Object.exports.getSession (/home/*/node_modules/@mysql/xdevapi/index.js:101:22)
    at Object.<anonymous> (/home/*/bug.js:3:8)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Function.Module.runMain (internal/modules/cjs/loader.js:877:12)

MySQL documents says any characters are accepted for password.
https://dev.mysql.com/doc/refman/8.0/en/user-names.html

> If the user name and password contain only ASCII characters, it is possible to connect to the > server regardless of character set settings. To enable connections when the user name or 
> password contain non-ASCII characters, client applications should call the mysql_options() 
> C API function with the MYSQL_SET_CHARSET_NAME option and appropriate character set > name as arguments. This causes authentication to take place using the specified character > set. Otherwise, authentication fails unless the server default character set is the same as the encoding in the authentication defaults.

How to repeat:
mysqlx = require('@mysql/xdevapi');

mysqlx.getSession('mysqlx://appuser:Password#123@hostname:33060').then(()=>{}).catch(err=>{console.log(err)})

Suggested fix:
check URI syntax only. do not check password characters.
[17 Nov 2019 5:28] MySQL Verification Team
Hello Mitani,

Thank you for the report and feedback.
Verified as described.

regards,
Umesh
[18 Jan 2020 10:37] Rui Quelhas
Sorry for the late answer and thank you for taking the time to write to us, but this is not a bug.

Connection strings or URIs are based on a convention that stems from RFC
3986. In such constructs, characters like the ones mentioned have a special
meaning, which means they need to be encoded somehow. In this case
'Password#123' would have to be encoded as 'Password%23123', where '#' is
encoded as '%23'. One way to do that in JavaScript, is by using the global
encodeURIComponent() function. So, the following would work as expected:

// using ES6 template strings
mysqlx.getSession(`mysqlx://appuser:${encodeURIComponent('Password#123')}@host
name:33060`)

// using string concatenation (for older ES versions)
mysqlx.getSession('mysqlx://appuser:' +  encodeURIComponent('Password#123') +
'@hostname:33060')

Alternatively, one can also use the API based on plain JavaScript Objects to
specify the connection properties. In this case, the following also works:

mysqlx.getSession({ user: 'appuser', password: 'Password#123', host:
'hostname' })

Also, bear in mind that Connector/Node.js is a client based on the X
Protocol, which means it does not use libmysqlclient, and consequently, does
not use C API mentioned in the documentation. The following links provide
more details about Connector/Node.js, the X DevAPI and the X Protocol.

https://dev.mysql.com/doc/dev/connector-nodejs/8.0/
https://dev.mysql.com/doc/x-devapi-userguide/en/
https://dev.mysql.com/doc/internals/en/x-protocol.html