- Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathMySqlConnectionStringBuilder.ts
119 lines (99 loc) · 5.89 KB
/
MySqlConnectionStringBuilder.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* The basic format of a connection string includes a series of keyword/value pairs separated by semicolons.
* The equal sign (=) connects each keyword and its value. (Ex: Key1=Val1;Key2=Val2)
*
* Following rules are to be followed while passing special characters in values:
1. To include values that contain a semicolon, single-quote character, or double-quote character, the value must be enclosed in double quotation marks.
2. If the value contains both a semicolon and a double-quote character, the value can be enclosed in single quotation marks.
3. The single quotation mark is also useful if the value starts with a double-quote character. Conversely, the double quotation mark can be used if the value starts with a single quotation mark.
4. If the value contains both single-quote and double-quote characters, the quotation mark character used to enclose the value must be doubled every time it occurs within the value.
Regex used by the parser(connectionStringParserRegex) to parse the VALUE:
('[^']*(''[^']*)*') -> value enclosed with single quotes and has consecutive single quotes
|("[^"]*(""[^"]*)*") -> value enclosed with double quotes and has consecutive double quotes
|((?!['"])[^;]*)) -> value does not start with quotes does not contain any special character. Here we do a positive lookahead to ensure that the value doesn't start with quotes which should have been handled in previous cases
Regex used to validate the entire connection string:
A connection string is considered valid if it is a series of key/value pairs separated by semicolons. Each key/value pair must satisy the connectionStringParserRegex to ensure it is a valid key/value pair.
^[;\s]*{KeyValueRegex}(;[;\s]*{KeyValueRegex})*[;\s]*$
where KeyValueRegex = ([\w\s]+=(?:('[^']*(''[^']*)*')|("[^"]*(""[^"]*)*")|((?!['"])[^;]*))))
*/
import*ascorefrom'@actions/core';
import{MySqlConnectionString}from'./MySqlConnectionString';
constconnectionStringParserRegex=/(?<key>[\w\s]+)=(?<val>('[^']*(''[^']*)*')|("[^"]*(""[^"]*)*")|((?!['"])[^;]*))/g
constconnectionStringTester=/^[;\s]*([\w\s]+=(?:('[^']*(''[^']*)*')|("[^"]*(""[^"]*)*")|((?!['"])[^;]*)))(;[;\s]*([\w\s]+=(?:('[^']*(''[^']*)*')|("[^"]*(""[^"]*)*")|((?!['"])[^;]*))))*[;\s]*$/
exportdefaultclassMySqlConnectionStringBuilderimplementsMySqlConnectionString{
constructor(connectionString: string){
this._connectionString=connectionString;
this._validateConnectionString();
this._parsedConnectionString=this._parseConnectionString();
}
publicgetconnectionString(): string{
returnthis._connectionString;
}
publicgetuserId(): string{
returnthis._parsedConnectionString.userId;
}
publicgetpassword(): string{
returnthis._parsedConnectionString.password;
}
publicgetserver(): string{
returnthis._parsedConnectionString.server;
}
publicgetdatabase(): string|null|undefined{
returnthis._parsedConnectionString.database;
}
private_validateConnectionString(){
if(!connectionStringTester.test(this._connectionString)){
thrownewError('Invalid connection string. A valid connection string is a series of keyword/value pairs separated by semi-colons. If there are any special characters like quotes, semi-colons in the keyword value, enclose the value within quotes. Refer this link for more info on conneciton string https://aka.ms/sqlconnectionstring');
}
}
private_parseConnectionString(): MySqlConnectionString{
letresult=this._connectionString.matchAll(connectionStringParserRegex);
letparsedConnectionString: MySqlConnectionString={}asany;
for(letmatchofresult){
if(match.groups){
letkey=match.groups.key.trim();
letval=match.groups.val.trim();
/**
* If the first character of val is a single/double quote and there are two consecutive single/double quotes in between,
* convert the consecutive single/double quote characters into one single/double quote character respectively (Point no. 4 above)
*/
if(val[0]==="'"){
val=val.slice(1,-1);
val=val.replace(/''/g,"'");
}
elseif(val[0]==='"'){
val=val.slice(1,-1);
val=val.replace(/""/g,'"');
}
switch(key.toLowerCase()){
case'user id':
case'uid': {
parsedConnectionString.userId=val;
break;
}
case'password':
case'pwd': {
parsedConnectionString.password=val;
// masking the connection string password to prevent logging to console
core.setSecret(val);
break;
}
case'database': {
parsedConnectionString.database=val;
break;
}
case'server': {
parsedConnectionString.server=val;
break;
}
}
}
}
if(!parsedConnectionString.server||!parsedConnectionString.userId||!parsedConnectionString.password){
thrownewError(`Missing required keys in connection string. Please ensure that the keys 'Server', 'User Id', 'Password' are provided in the connection string.`);
}
returnparsedConnectionString;
}
private_connectionString: string='';
private_parsedConnectionString: MySqlConnectionString;
}