nodejs writeFile only working with admin permssions - node.js

I currently learning electron and I would like to write a config file in the same dir than the exe file. This is my code:
var save = fs.readFileSync(__dirname+"/config.json")
save = {
storein : savegame
}
fs.writeFile("./config.json", JSON.stringify(save), function(error){
//other stuff
})
But if I run this without administrator permissions, its not working, only if I run the .exe as an admin. If I use electron app it works too

Related

cloud run application to create file via api call and store the file in gcs bucket

I have created an application via nodeJS which creates a JSON file when I hit the PUT API.. via Postman. This file needs to be stored in GCS Bucket.
All of this works fine when I run the application locally.. file gets created and gets uploaded to my GCS bucket, but when I deploy the application to Cloud Run it does not work.... nor do I see any error in logs.
I have also added a member which is same service account used to create Cloud Run application and given it Legacy Bucket Owner role.
Below is my code snippet of PUT Block:
app.put('/api/ddr/:ticket_id', (req, res) => {
const ticket_id = req.params.ticket_id;
const requestBody = req.body;
if(!requestBody || !ticket_id){
res.status(404).send({message: 'There is an error'});
}
var fs = require('fs');
var writer = fs.createWriteStream(filename,{ 'flags': 'a'
, 'encoding': null
, 'mode': 0666
});
writer.write(JSON.stringify(requestBody)+',');
console.log('Filename is ' +filename);
res.status(201).send('all ok');
});
Also, please find below code snippet for uploading the file:
async function uploadFile() {
await storage.bucket(bucketName).upload(filePath);
console.log(`${filePath} uploaded to ${bucketName}`);
}
uploadFile().catch(console.error);
EDIT: The problem seems with my Dockerfile because when I run my application via nodemon the application works as expected but when i run the docker ... the application does not seem to work properly.. I don't know much about setting up a DockerFile.. Help will be very much appreciated... Below is my Docker code:
FROM node:14.8.0-slim
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
CMD ["npm", "start"]

How to read contents of a directory in linux on nodejs?

I am creating an application on nodejs that has to read contents of a folder in the install location. The installer creates the directory 'cert' at the install location.
My code is:
const dircert = './cert'
files = fs.readdirSync(dircert)
if (!files.length) {
***some code***
} else {
files.forEach(file => {
if (path.extname(file) == '.key') {
pathkey = path.resolve(dircert, file)
}
if (path.extname(file) == '.crt') {
pathcert = path.resolve(dircert, file)
}
})
This runs fine in windows but not in Linux. The installer is not able to read the contents. What do I need to change to ensure that it works in both? I am pretty new to linux.
The application is getting installed in ProgramFiles in windows but in /opt/AppName in linux. Please suggest.
Editing to add: So this cert folder is getting created under /opt/AppName/ in linux and under c:/ProgramFiles/company/App Name/ in Windows. While this code runs fine on windows, on linux this code tries to look for cert at root. How do I make sure it looks for the folder at the installed location which is /opt/AppName, and it should work on both the platforms.
It's unclear from your question how the files are being installed and how the code is being executed. Both of these matter in Linux. You can use the __dirname node variable with path.resolve() to get the directory of the current module. If cert is below the current module, you can use the following code to resolve the location:
const path = require('path');
const dircert = path.resolve(__dirname, 'cert');
If you're using ES Modules:
import path from 'path';
const dircert = path.resolve('cert').

How to pass the dotenv config path through a Windows service created with node-windows

Windows Server 2008 R2 Enterprise
Node version 12.13.1
node-windows version 1.0.0-beta.5
When I call my node application, instead of using require('dotenv') in code to load the environment variables (e.g. from a default .env file), I need to pass the path to a specific environment file. This environemnt file is different depending for which customer the application is started for (e.g. different database, paths, customer code, etc..).
In the cli, I can succesfully do it this way:
node --require dotenv/config bin/www dotenv_config_path=C:\projects\abc\env\XYZ.env
As you can see I use an absolute path for the location of the env file, but it also works with a relative path. I'm just trying to eliminate this as a reason why I can't make this work with node-windows.
I'm trying to use node-windows to create a Windows service wrapper that calls my node application and also loads a specific env file like the above code does. Can't make it work so far, after creating the Windows service, it quits after a moment, which tells me it's missing the environment variables it needs to function. Which means it can't load of find the environment file.
Here is my script to create the Windows service using node-windows:
#!/usr/bin/env node
// Usage:
// npm run install-win XYZ
// Notes:
// 1. Before creating the windows service, make sure to delete any previous files in the /bin folder (i.e. all files abcXYZ.*)
// 2. After creating the windows service, change the Log On account to the ******* user to avoid persmission issues when using paths on other production servers
const args = process.argv;
const codeclient = args[2];
const serviceName = `abc${codeclient}`;
const environmentPath = `C:\\projects\\abc\\abc-api\\env\\${codeclient}.env`; // Make sure to use the full absolute path here
const Service = require('node-windows').Service;
// Create a new service object
const svc = new Service({
name: serviceName,
description: serviceName,
script: require('path').join(__dirname, 'www'),
scriptOptions: `dotenv_config_path=${environmentPath}`,
nodeOptions: [
'--require=dotenv/config',
'--harmony',
'--max_old_space_size=4096'
]/*,
env: {
name: 'DOTENV_CONFIG_PATH',
value: environmentPath
}*/
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install', function(){
svc.start();
});
svc.install();
I've tried both the "scriptOptions" approach and the "env" approach in various configurations, but nothing works.
If anyone has managed to make something like this work before, I'd very much like to know how you did it.
So the way I ended up doing this is instead just pass my codeclient variable through the scriptOptions of node-windows, and then using that in my node application to have dotenv load a specific env file. It's more simple really.
The only issue I had with the approach is that node-windows would fail with my numerical codeclient, always assuming it's a number type instead of a string (node-windows tries to call String.split() on it later). I had to append the underscore in front to force it as a string.
Script to create the Windows service with node-windows:
#!/usr/bin/env node
// Usage:
// npm run install-win 123
// Notes:
// 1. Before creating the windows service, make sure to delete any previous files in the /bin folder (i.e. all files abc123.*)
// 2. After creating the windows service, change the Log On account of the service to the ******** user to avoid persmission issues when using paths on other production servers
const args = process.argv;
const codeclient = args[2];
const serviceName = `abc${codeclient}`;
const Service = require('node-windows').Service;
// Create a new service object
const svc = new Service({
name: serviceName,
description: serviceName,
script: require('path').join(__dirname, 'www'),
scriptOptions: `_${codeclient}`,
nodeOptions: [
'--harmony',
'--max_old_space_size=4096'
]
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install', function(){
svc.start();
});
svc.install();
Loading the env file in the node application:
// Load environment variables into process.env
if (process.argv[2]) {
// Load a specific env file for the codeclient passed as argument
const codeclient = process.argv[2].replace('_', '');
require('dotenv').config({ path: `./env/${codeclient}.env` });
}
else {
// Load the default .env file
require('dotenv').config();
}

Electron open file/directory in specific application

I'm building a sort of File explorer / Finder using Electron.
I want to open some file types with a specific application.
I've tried the approach from this answer:
Open external file with Electron
import { spawn } from 'child_process'
spawn('/path/to/app/superApp.app', ['/path/to/file'])
But when I do that, I get a EACCES error as follows.
Is this the right approach? If yes, how can I fix the issue? If not, what is the right approach?
You can open a file or folder through shell commands from the electron module. The commands work on both main and renderer process.
const {shell} = require('electron') // deconstructing assignment
shell.showItemInFolder('filepath') // Show the given file in a file manager. If possible, select the file.
shell.openPath('folderpath') // Open the given file in the desktop's default manner.
More info on https://github.com/electron/electron/blob/master/docs/api/shell.md
While the accepted answer does say how to open the folder in file explorer, it doesn't answer the question on how to open the folder WITH an external program like VSCode. It can be done like so:
import { spawn, SpawnOptions } from "child_process";
import { pathExists } from "fs-extra";
const editorPath = "C:/Program Files/Microsoft VS Code/Code.exe";
export const launchExternalEditor = async (
folderPath: string
): Promise<void> => {
const exists = await pathExists(editorPath);
if (!exists) {
console.error("editor not found");
}
const opts: SpawnOptions = {
// Make sure the editor processes are detached from the Desktop app.
// Otherwise, some editors (like Notepad++) will be killed when the
// Desktop app is closed.
detached: true,
};
spawn(editorPath, [folderPath], opts);
};
This will launch the folder in VSCode as it's root directory. Code is taken from this repository.
Note: this may require some tinkering depending on what program you are trying to use, but so far it worked properly with: VSCode, Visual Studio 2019, Intellij IDEA, NetBeans.
For display native system dialogs for opening and saving files, alerting, etc. you can use dialog module from electron package.
const electron = require('electron');
var filePath = __dirname;
console.log(electron.dialog.showOpenDialog)({
properties:['openFile'],
filters:[
{name:'Log', extentions:['csv', 'log']}
]
});
A very prompt explanation is provided at Electron Docs.

Node.js as service, exec doesn't work

I'm running Node.js project as service using nssm. When user clicks button on my nodejs website it should run
require('child_process').exec('cmd /c batfile.bat', function({ res.send(somedata); });
but instead it just skips running bat file and jumps to res.send(somedata). Why is that?
When I run Node.js using cmd and npm start server.js it works fine. How can I make exec work while running nodejs as service?
Edit, some code:
require('child_process').exec('cmd /c batfile.bat', function(){
var log = fs.readFileSync('logs/batlog.log', 'utf8');
var html = fs.readFileSync('logs/batlog.htm', 'utf8');
var json = {"log": log, "html": html};
res.send(json);
});
and the batfile.bat is supposed to generate those 2 files but it just doesn't if I run nodejs as service.

Resources