How to scape special characters for linux, nodejs exec function - node.js

I'm running this ffmpeg command on my linux server and while I paste it into the terminal, it works just fine but as soon as I use execPromise to run the EXACT same command, it returns an error.
const { exec } = require('child_process');
const { promisify } = require('util');
const execPromise = promisify(exec);
const encode = async ffmpegCode => {
try {
console.log(ffmpegCode) //Here I can see that the code is the
//exact same one than the one that works
//when pasted into the terminal
await execPromise(ffmpegCode);
return 200
} catch (err) {
console.log(err)
}
}
I need \: to be interpreted as such. When I type it as is, \:, the error message shows me that it interpreted it as : which is expected.
If I pass in \\:, I expect it to interpret it as I need it which would be \: but the error shows me that it interprets it as \\:.
\\\: is interpreted as \\: and \\\\: is interpreted as \\\\:.
Part of the command passed:
...drawtext=text='timestamp \\: %{pts \\: localtime \\: 1665679092.241...
Expected command:
...drawtext=text='timestamp \: %{pts \: localtime \: 1665679092.241...
Error message:
...drawtext=text='timestamp \\: %{pts \\: localtime \\: 1665679092.241...
How do I get /: through to the exec function?

It looks like the issue might be related to escaping special characters in the ffmpegCode string. The execPromise function is interpreting the backslash character () as an escape character, which is modifying the string passed to ffmpeg in unexpected ways.
To properly escape special characters in the ffmpegCode string, you can use the built-in JSON.stringify() function. This function properly escapes special characters in a string and produces a valid JSON string that can be passed as an argument to execPromise.
Here's an updated encode function that uses JSON.stringify() to properly escape the ffmpegCode string:
const encode = async ffmpegCode => {
try {
console.log(ffmpegCode);
const command = `ffmpeg ${JSON.stringify(ffmpegCode)}`;
await execPromise(command);
return 200;
} catch (err) {
console.log(err);
}
};
By wrapping the ffmpegCode string with JSON.stringify(), the backslashes and other special characters will be properly escaped, allowing the execPromise function to properly execute the ffmpeg command.
Note that the resulting command string will be wrapped in double quotes, so you may need to modify your ffmpeg command to properly handle quoted arguments.

Related

Buffer.from(base64EncodedString, 'base64').toString('binary') vs 'utf8'

In Node.js: Why does this test fail on the second call of main?
test('base64Encode and back', () => {
function main(input: string) {
const base64string = base64Encode(input);
const text = base64Decode(base64string);
expect(input).toEqual(text);
}
main('demo');
main('😉😉😉');
});
Here are my functions:
export function base64Encode(text: string): string {
const buffer = Buffer.from(text, 'binary');
return buffer.toString('base64');
}
export function base64Decode(base64EncodedString: string): string {
const buffer = Buffer.from(base64EncodedString, 'base64');
return buffer.toString('binary');
}
From these pages, I figured I had written these functions correctly so that one would reverse the other:
https://github.com/node-browser-compat/btoa/blob/master/index.js
https://github.com/node-browser-compat/atob/blob/master/node-atob.js
https://stackoverflow.com/a/47890385/470749
If I change the 'binary' options to be 'utf8'instead, the test passes.
But my database currently has data where this function only seems to work if I use 'binary'.
binary is an alias for latin1
'latin1': Latin-1 stands for ISO-8859-1. This character encoding only supports the Unicode characters from U+0000 to U+00FF. Each character is encoded using a single byte. Characters that do not fit into that range are truncated and will be mapped to characters in that range.
This character set is unable to display multibyte utf8 characters.
To get utf8 multibyte characters back, go directly to base64 and back again
function base64Encode(str) {
return Buffer.from(str).toString('base64')
}
function base64Decode(str) {
return Buffer.from(str, 'base64').toString()
}
> base64Encode('😉')
'8J+YiQ=='
> base64Decode('8J+YiQ==')
'😉'

How to fix this issue in my code (Node.js&Discord.js): "node:8036"?

I'm started programming yesterday and i wanted to make a bot. I have a small issue and I can't fix him. Error = "(node:8188) UnhandledPromiseRejectionWarning: ReferenceError: bread is not defined". Line of code = "return message.channel.send({files: [bread.png]});". Thank you in advance.
bot.on('message', async message => {
let prefix = '!';
let messageArray = message.content.split(" ");
let cmd = messageArray[0];
let args = messageArray.slice(1);
if(cmd === `${prefix}bulka`) {
return message.channel.send({files: [bread.png]});
}
})
There is a syntax error in this line:
return message.channel.send({files: [bread.png]});
Use:
return message.channel.send({files: ["bread.png"]});
If you want to use a string inside an array, you need to wrap the text in single quotes ('), double quotes ("), or grave accents (`) to let JS know that it's a literal string. If you use bread.png, Node.js looks for the global object or variable bread and its property png.

Spawn in nodejs for a unix command with spaces in parameters

I would like to execute the following command using nodejs Spawn on a Debian system :
/usr/bin/apt-get upgrade -s | tail -1 | cut -f1 -d' '
I want to use spawn and not exec because of future use of root only commands and i don't want to allow a full shell access (i will update the visudo file with correct commands)
Here is my code
const apt = spawn('/usr/bin/apt-get', ['upgrade', '-s']);
const tail = spawn('tail', ['-1']);
const cut = spawn('cut', ['-f1', '-d" "']);
apt.stdout.on('data', (data) => {
tail.stdin.write(data);
});
tail.stdout.on('data', (data) => {
cut.stdin.write(data);
});
cut.stdout.on('data', (data) => {
console.log(data.toString());
});
apt.stderr.on('data', (data) => {
console.log("apt stderr: ${data}");
});
tail.stderr.on('data', (data) => {
console.log("tail stderr: ${data}");
});
cut.stderr.on('data', (data) => {
console.log("cut stderr: ${data}");
});
apt.on('close', (code) => {
if (code !== 0) {
console.log("apt process exited with code ${code}");
}
});
tail.on('close', (code) => {
if (code !== 0) {
console.log("tail process exited with code ${code}");
}
});
cut.on('close', (code) => {
if (code !== 0) {
console.log("cut process exited with code ${code}");
}
});
res.status(200).json('');
Once executed i have an error because of the '-d" "' parameter that is not recognized. I try escaping the space with a double \ or split the parameter in both but still errors
It should just be:
const cut = spawn('cut', ['-f1', '-d ']);
No double quotes or backslash escapes -- those are for the use of the shell, not cut, and there's no shell here.
This makes dealing with unknown filenames (for your future use cases) particularly easy: When your strings are passed as arguments (to software that doesn't misuse them my running eval-equivalent code later), you don't need to quote, escape, sanitize, or otherwise modify them before they can be passed as data.
(That is to say -- when you tell your shell cut -f1 -d" ", the actual syscall it invokes to start that cut process, in C syntax, looks like execve("/usr/bin/cut", {"cut", "-f1", "-d ", NULL}, environ); the quotes were syntactic, consumed by the shell when it used them to make the decision that the space after the -d should be part of the same literal argument).

Invalid character entity parsing xml

I am trying to parse a string of xml and I getting an error
[Error: Invalid character entity
Line: 0
Column: 837
Char: ]
Does xml not like brackets? Do I need to replace all the brackets with something like \\]. Thanks
Ok, the invalid character was the dash and an &. I fixed it by doing the following:
xml = data.testSteps.replace(/[\n\r]/g, '\\n')
.replace(/&/g,"&")
.replace(/-/g,"-");
Thanks
Using a node domparser will get around having to do a string replace on every character that is not easily parsed as a string. This is especially useful if you have a large amount of XML to parse that may have different characters.
I would recommend xmldom as I have used it successfully with xml2js
The combined usage looks like the following:
var parseString = require('xml2js').parseString;
var DOMParser = require('xmldom').DOMParser;
var xmlString = "<test>some stuff </test>";
var xmlStringSerialized = new DOMParser().parseFromString(xmlString, "text/xml");
parseString(xmlStringSerialized, function (err, result) {
if (err) {
//did not work
} else {
//worked! use JSON.stringify()
var allDone = JSON.stringify(result);
}
});

How can I parse a string into appropriate arguments for child_process.spawn?

I want to be able to take a command string, for example:
some/script --option="Quoted Option" -d --another-option 'Quoted Argument'
And parse it into something that I can send to child_process.spawn:
spawn("some/script", ["--option=\"Quoted Option\"", "-d", "--another-option", "Quoted Argument"])
All of the parsing libraries I've found (e.g. minimist, etc.) do too much here by parsing it into some kind of options object, etc. I basically want the equivalent of whatever Node does to create process.argv in the first place.
This seems like a frustrating hole in the native APIs since exec takes a string, but doesn't execute as safely as spawn. Right now I'm hacking around this by using:
spawn("/bin/sh", ["-c", commandString])
However, I don't want this to be tied to UNIX so strongly (ideally it'd work on Windows too). Halp?
Standard Method (no library)
You don't have to parse the command string into arguments, there's an option on child_process.spawn named shell.
options.shell
If true, runs command inside of a shell.
Uses /bin/sh on UNIX, and cmd.exe on Windows.
Example:
let command = `some_script --option="Quoted Option" -d --another-option 'Quoted Argument'`
let process = child_process.spawn(command, [], { shell: true }) // use `shell` option
process.stdout.on('data', (data) => {
console.log(data)
})
process.stderr.on('data', (data) => {
console.log(data)
})
process.on('close', (code) => {
console.log(code)
})
The minimist-string package might be just what you're looking for.
Here's some sample code that parses your sample string -
const ms = require('minimist-string')
const sampleString = 'some/script --option="Quoted Option" -d --another-option \'Quoted Argument\'';
const args = ms(sampleString);
console.dir(args)
This piece of code outputs this -
{
_: [ 'some/script' ],
option: 'Quoted Option',
d: true,
'another-option': 'Quoted Argument'
}

Resources