Commit 35b88fcff867a075baccb66fafb24ca9b0dd01fa

Michael Schmidt 2021-09-06T17:51:54

Shell-session: Fixed command false positives (#3048) * Shell-session: Fixed command false positives * Fixed comments and `<` characters

diff --git a/components/prism-shell-session.js b/components/prism-shell-session.js
index 9ec763f..1b67ed7 100644
--- a/components/prism-shell-session.js
+++ b/components/prism-shell-session.js
@@ -18,11 +18,22 @@
 		'command': {
 			pattern: RegExp(
 				// user info
-				/^(?:[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+(?::[^\0-\x1F$#%*?"<>:;|]+)?|[^\0-\x1F$#%*?"<>@:;|]+)?/.source +
+				/^/.source +
+				'(?:' +
+				(
+					// <user> ":" ( <path> )?
+					/[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+(?::[^\0-\x1F$#%*?"<>:;|]+)?/.source +
+					'|' +
+					// <path>
+					// Since the path pattern is quite general, we will require it to start with a special character to
+					// prevent false positives.
+					/[/~.][^\0-\x1F$#%*?"<>@:;|]*/.source
+				) +
+				')?' +
 				// shell symbol
-				/[$#%]/.source +
+				/[$#%](?=\s)/.source +
 				// bash command
-				/(?:[^\\\r\n'"<$]|\\(?:[^\r]|\r\n?)|\$(?!')|<<str>>)+/.source.replace(/<<str>>/g, function () { return strings; }),
+				/(?:[^\\\r\n \t'"<$]|[ \t](?:(?!#)|#.*$)|\\(?:[^\r]|\r\n?)|\$(?!')|<(?!<)|<<str>>)+/.source.replace(/<<str>>/g, function () { return strings; }),
 				'm'
 			),
 			greedy: true,
diff --git a/components/prism-shell-session.min.js b/components/prism-shell-session.min.js
index 208c65f..7481032 100644
--- a/components/prism-shell-session.min.js
+++ b/components/prism-shell-session.min.js
@@ -1 +1 @@
-!function(s){var n=['"(?:\\\\[^]|\\$\\([^)]+\\)|\\$(?!\\()|`[^`]+`|[^"\\\\`$])*"',"'[^']*'","\\$'(?:[^'\\\\]|\\\\[^])*'","<<-?\\s*([\"']?)(\\w+)\\1\\s[^]*?[\r\n]\\2"].join("|");s.languages["shell-session"]={command:{pattern:RegExp('^(?:[^\\s@:$#%*!/\\\\]+@[^\r\n@:$#%*!/\\\\]+(?::[^\0-\\x1F$#%*?"<>:;|]+)?|[^\0-\\x1F$#%*?"<>@:;|]+)?[$#%]'+"(?:[^\\\\\r\n'\"<$]|\\\\(?:[^\r]|\r\n?)|\\$(?!')|<<str>>)+".replace(/<<str>>/g,function(){return n}),"m"),greedy:!0,inside:{info:{pattern:/^[^#$%]+/,alias:"punctuation",inside:{user:/^[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+/,punctuation:/:/,path:/[\s\S]+/}},bash:{pattern:/(^[$#%]\s*)\S[\s\S]*/,lookbehind:!0,alias:"language-bash",inside:s.languages.bash},"shell-symbol":{pattern:/^[$#%]/,alias:"important"}}},output:/.(?:.*(?:[\r\n]|.$))*/},s.languages["sh-session"]=s.languages.shellsession=s.languages["shell-session"]}(Prism);
\ No newline at end of file
+!function(s){var n=['"(?:\\\\[^]|\\$\\([^)]+\\)|\\$(?!\\()|`[^`]+`|[^"\\\\`$])*"',"'[^']*'","\\$'(?:[^'\\\\]|\\\\[^])*'","<<-?\\s*([\"']?)(\\w+)\\1\\s[^]*?[\r\n]\\2"].join("|");s.languages["shell-session"]={command:{pattern:RegExp('^(?:[^\\s@:$#%*!/\\\\]+@[^\r\n@:$#%*!/\\\\]+(?::[^\0-\\x1F$#%*?"<>:;|]+)?|[/~.][^\0-\\x1F$#%*?"<>@:;|]*)?[$#%](?=\\s)'+"(?:[^\\\\\r\n \t'\"<$]|[ \t](?:(?!#)|#.*$)|\\\\(?:[^\r]|\r\n?)|\\$(?!')|<(?!<)|<<str>>)+".replace(/<<str>>/g,function(){return n}),"m"),greedy:!0,inside:{info:{pattern:/^[^#$%]+/,alias:"punctuation",inside:{user:/^[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+/,punctuation:/:/,path:/[\s\S]+/}},bash:{pattern:/(^[$#%]\s*)\S[\s\S]*/,lookbehind:!0,alias:"language-bash",inside:s.languages.bash},"shell-symbol":{pattern:/^[$#%]/,alias:"important"}}},output:/.(?:.*(?:[\r\n]|.$))*/},s.languages["sh-session"]=s.languages.shellsession=s.languages["shell-session"]}(Prism);
\ No newline at end of file
diff --git a/tests/languages/shell-session/command_string_feature.test b/tests/languages/shell-session/command_string_feature.test
index 854314b..930d0b6 100644
--- a/tests/languages/shell-session/command_string_feature.test
+++ b/tests/languages/shell-session/command_string_feature.test
@@ -21,6 +21,9 @@ $ cat << "EOF" > /etc/ipsec.secrets
 # : RSA vpn-server-b.key
 EOF
 
+$ LC_ALL=C tr -cd 'a-zA-Z0-9_-;:!?.@\\*/#%$' < /dev/random | head -c 8
+y_#!$U48
+
 ----------------------------------------------------
 
 [
@@ -64,10 +67,10 @@ EOF
 			["builtin", "echo"],
 			["punctuation", "\\"],
 			"'a ",
-			["comment", "# "]
+			["comment", "# '"]
 		]]
 	]],
-	["output", "'\r\n\r\n"],
+
 	["command", [
 		["shell-symbol", "$"],
 		["bash", [
@@ -83,7 +86,28 @@ EOF
 				"\r\n: RSA vpn-server-a.key\r\n# : RSA vpn-server-b.key\r\nEOF"
 			]]
 		]]
-	]]
+	]],
+
+	["command", [
+		["shell-symbol", "$"],
+		["bash", [
+			["assign-left", [
+				["environment", "LC_ALL"]
+			]],
+			["operator", ["="]],
+			"C ",
+			["function", "tr"],
+			" -cd ",
+			["string", "'a-zA-Z0-9_-;:!?.@\\\\*/#%$'"],
+			["operator", ["<"]],
+			" /dev/random ",
+			["operator", ["|"]],
+			["function", "head"],
+			" -c ",
+			["number", "8"]
+		]]
+	]],
+	["output", "y_#!$U48"]
 ]
 
 ----------------------------------------------------
diff --git a/tests/languages/shell-session/issue3047_1.test b/tests/languages/shell-session/issue3047_1.test
new file mode 100644
index 0000000..ca9eec6
--- /dev/null
+++ b/tests/languages/shell-session/issue3047_1.test
@@ -0,0 +1,96 @@
+$ diskutil list
+/dev/disk0 (internal, physical):
+   #:                       TYPE NAME                    SIZE       IDENTIFIER
+   0:      GUID_partition_scheme                        *500.3 GB   disk0
+   1:                        EFI EFI                     209.7 MB   disk0s1
+   2:                 Apple_APFS Container disk1         500.1 GB   disk0s2
+
+/dev/disk1 (synthesized):
+   #:                       TYPE NAME                    SIZE       IDENTIFIER
+   0:      APFS Container Scheme -                      +500.1 GB   disk1
+                                 Physical Store disk0s2
+   1:                APFS Volume Macintosh HD - Data     340.9 GB   disk1s1
+   2:                APFS Volume Preboot                 85.9 MB    disk1s2
+   3:                APFS Volume Recovery                529.0 MB   disk1s3
+   4:                APFS Volume VM                      3.2 GB     disk1s4
+   5:                APFS Volume Macintosh HD            11.3 GB    disk1s5
+
+/dev/disk2 (internal, physical):
+   #:                       TYPE NAME                    SIZE       IDENTIFIER
+   0:     FDisk_partition_scheme                        *15.9 GB    disk2
+   1:             Windows_FAT_32 boot                    268.4 MB   disk2s1
+   2:                      Linux                         15.7 GB    disk2s2
+
+$ sudo diskutil unmount /dev/diskn
+disk2 was already unmounted or it has a partitioning scheme so use "diskutil unmountDisk" instead
+
+$ sudo diskutil unmountDisk /dev/diskn (if previous step fails)
+Unmount of all volumes on disk2 was successful
+
+$ sudo dd bs=1m if=$HOME/Downloads/tails-amd64-4.18.img of=/dev/rdiskn
+1131+0 records in
+1131+0 records out
+1185939456 bytes transferred in 44.708618 secs (26525970 bytes/sec)
+
+$ sudo diskutil unmountDisk /dev/diskn
+Unmount of all volumes on disk2 was successful
+
+----------------------------------------------------
+
+[
+	["command", [
+		["shell-symbol", "$"],
+		["bash", ["diskutil list"]]
+	]],
+
+	["output", "/dev/disk0 (internal, physical):\r\n   #:                       TYPE NAME                    SIZE       IDENTIFIER\r\n   0:      GUID_partition_scheme                        *500.3 GB   disk0\r\n   1:                        EFI EFI                     209.7 MB   disk0s1\r\n   2:                 Apple_APFS Container disk1         500.1 GB   disk0s2\r\n\r\n/dev/disk1 (synthesized):\r\n   #:                       TYPE NAME                    SIZE       IDENTIFIER\r\n   0:      APFS Container Scheme -                      +500.1 GB   disk1\r\n                                 Physical Store disk0s2\r\n   1:                APFS Volume Macintosh HD - Data     340.9 GB   disk1s1\r\n   2:                APFS Volume Preboot                 85.9 MB    disk1s2\r\n   3:                APFS Volume Recovery                529.0 MB   disk1s3\r\n   4:                APFS Volume VM                      3.2 GB     disk1s4\r\n   5:                APFS Volume Macintosh HD            11.3 GB    disk1s5\r\n\r\n/dev/disk2 (internal, physical):\r\n   #:                       TYPE NAME                    SIZE       IDENTIFIER\r\n   0:     FDisk_partition_scheme                        *15.9 GB    disk2\r\n   1:             Windows_FAT_32 boot                    268.4 MB   disk2s1\r\n   2:                      Linux                         15.7 GB    disk2s2\r\n\r\n"],
+	["command", [
+		["shell-symbol", "$"],
+		["bash", [
+			["function", "sudo"],
+			" diskutil unmount /dev/diskn"
+		]]
+	]],
+
+	["output", "disk2 was already unmounted or it has a partitioning scheme so use \"diskutil unmountDisk\" instead\r\n\r\n"],
+	["command", [
+		["shell-symbol", "$"],
+		["bash", [
+			["function", "sudo"],
+			" diskutil unmountDisk /dev/diskn ",
+			["punctuation", "("],
+			"if previous step fails",
+			["punctuation", ")"]
+		]]
+	]],
+
+	["output", "Unmount of all volumes on disk2 was successful\r\n\r\n"],
+	["command", [
+		["shell-symbol", "$"],
+		["bash", [
+			["function", "sudo"],
+			["function", "dd"],
+			["assign-left", ["bs"]],
+			["operator", ["="]],
+			"1m ",
+			["assign-left", ["if"]],
+			["operator", ["="]],
+			["environment", "$HOME"],
+			"/Downloads/tails-amd64-4.18.img ",
+			["assign-left", ["of"]],
+			["operator", ["="]],
+			"/dev/rdiskn"
+		]]
+	]],
+
+	["output", "1131+0 records in\r\n1131+0 records out\r\n1185939456 bytes transferred in 44.708618 secs (26525970 bytes/sec)\r\n\r\n"],
+	["command", [
+		["shell-symbol", "$"],
+		["bash", [
+			["function", "sudo"],
+			" diskutil unmountDisk /dev/diskn"
+		]]
+	]],
+
+	["output", "Unmount of all volumes on disk2 was successful"]
+]
diff --git a/tests/languages/shell-session/issue3047_2.test b/tests/languages/shell-session/issue3047_2.test
new file mode 100644
index 0000000..40e03e6
--- /dev/null
+++ b/tests/languages/shell-session/issue3047_2.test
@@ -0,0 +1,43 @@
+$ gpg --card-status
+Reader ...........: Yubico YubiKey CCID
+Application ID ...: D*******************************
+Application type .: OpenPGP
+Version ..........: 0.0
+Manufacturer .....: Yubico
+Serial number ....: 1*******
+Name of cardholder: John Doe
+Language prefs ...: en
+Salutation .......:
+URL of public key : [not set]
+Login data .......: john@example.net
+Signature PIN ....: not forced
+Key attributes ...: ed25519 cv25519 ed25519
+Max. PIN lengths .: 127 127 127
+PIN retry counter : 3 0 3
+Signature counter : 0
+KDF setting ......: off
+UIF setting ......: Sign=on Decrypt=on Auth=on
+Signature key ....: ACE1 3F15 90C1 A8C9 D942  51E3 02ED C61B 6543 509B
+      created ....: 2021-07-21 18:44:34
+Encryption key....: 0524 00F4 8E1D 085A F3E1  61EC D463 4E0D 6E2D D8BF
+      created ....: 2021-07-21 18:44:52
+Authentication key: A27B 582F 1F62 03BA 549B  3D44 1E7B 69B2 38FF A21B
+      created ....: 2021-07-21 18:45:13
+General key info..: sub  ed25519/0x02EDC61B6543509B 2021-07-21 John Doe <john@example.net>
+sec#  ed25519/0xC2709D13BAB4763C  created: 2021-07-21  expires: never
+ssb>  ed25519/0x02EDC61B6543509B  created: 2021-07-21  expires: 2022-07-21
+                                  card-no: 0006 1*******
+ssb>  cv25519/0xD4634E0D6E2DD8BF  created: 2021-07-21  expires: 2022-07-21
+                                  card-no: 0006 1*******
+ssb>  ed25519/0x1E7B69B238FFA21B  created: 2021-07-21  expires: 2022-07-21
+                                  card-no: 0006 1*******
+
+----------------------------------------------------
+
+[
+	["command", [
+		["shell-symbol", "$"],
+		["bash", ["gpg --card-status"]]
+	]],
+	["output", "Reader ...........: Yubico YubiKey CCID\r\nApplication ID ...: D*******************************\r\nApplication type .: OpenPGP\r\nVersion ..........: 0.0\r\nManufacturer .....: Yubico\r\nSerial number ....: 1*******\r\nName of cardholder: John Doe\r\nLanguage prefs ...: en\r\nSalutation .......:\r\nURL of public key : [not set]\r\nLogin data .......: john@example.net\r\nSignature PIN ....: not forced\r\nKey attributes ...: ed25519 cv25519 ed25519\r\nMax. PIN lengths .: 127 127 127\r\nPIN retry counter : 3 0 3\r\nSignature counter : 0\r\nKDF setting ......: off\r\nUIF setting ......: Sign=on Decrypt=on Auth=on\r\nSignature key ....: ACE1 3F15 90C1 A8C9 D942  51E3 02ED C61B 6543 509B\r\n      created ....: 2021-07-21 18:44:34\r\nEncryption key....: 0524 00F4 8E1D 085A F3E1  61EC D463 4E0D 6E2D D8BF\r\n      created ....: 2021-07-21 18:44:52\r\nAuthentication key: A27B 582F 1F62 03BA 549B  3D44 1E7B 69B2 38FF A21B\r\n      created ....: 2021-07-21 18:45:13\r\nGeneral key info..: sub  ed25519/0x02EDC61B6543509B 2021-07-21 John Doe <john@example.net>\r\nsec#  ed25519/0xC2709D13BAB4763C  created: 2021-07-21  expires: never\r\nssb>  ed25519/0x02EDC61B6543509B  created: 2021-07-21  expires: 2022-07-21\r\n                                  card-no: 0006 1*******\r\nssb>  cv25519/0xD4634E0D6E2DD8BF  created: 2021-07-21  expires: 2022-07-21\r\n                                  card-no: 0006 1*******\r\nssb>  ed25519/0x1E7B69B238FFA21B  created: 2021-07-21  expires: 2022-07-21\r\n                                  card-no: 0006 1*******"]
+]