Is there a way of Creating lnk file using javascript - javascript

I would like to give the users in my website the ability to download a "lnk" file.
My idea is to generate this file with to contain an address that can be used only once.
Is there a way to generate this file in javascript?
The flow is something like -
the user presses a button
the javascript generates this file and downloads it to the user's machine
the user sends this file to another user to use this one-time-address from his machine
Is something like this is doable in javascript from the client side? or would i need to generate this file using java server side?

This is a faithful translation of mslink.sh.
I only tested my answer in Windows 8.1, but I would think that it works in older versions of Windows, too.
function create_lnk_blob(lnk_target) {
function hex_to_arr(s) {
var result = Array(s.length / 2);
for (var i = 0; i < result.length; ++i) {
result[i] = +('0x' + s.substr(2*i, 2));
}
return result;
}
function str_to_arr(s) {
var result = Array(s.length);
for (var i = 0; i < s.length; ++i) {
var c = s.charCodeAt(i);
if (c >= 128) {
throw Error("Only ASCII paths are suppored :-(");
}
result[i] = c;
}
return result;
}
function convert_CLSID_to_DATA(s) {
var idx = [[6,2], [4,2], [2,2], [0,2],
[11,2], [9,2], [16,2], [14,2],
[19,4], [24,12]];
var s = idx.map(function (ii) {
return s.substr(ii[0], ii[1]);
});
return hex_to_arr(s.join(''));
}
function gen_IDLIST(s) {
var item_size = (0x10000 + s.length + 2).toString(16).substr(1);
return hex_to_arr(item_size.replace(/(..)(..)/, '$2$1')).concat(s);
}
var HeaderSize = [0x4c, 0x00,0x00,0x00],
LinkCLSID = convert_CLSID_to_DATA("00021401-0000-0000-c000-000000000046"),
LinkFlags = [0x01,0x01,0x00,0x00], // HasLinkTargetIDList ForceNoLinkInfo
FileAttributes_Directory = [0x10,0x00,0x00,0x00],
FileAttributes_File = [0x20,0x00,0x00,0x00],
CreationTime = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
AccessTime = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
WriteTime = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
FileSize = [0x00,0x00,0x00,0x00],
IconIndex = [0x00,0x00,0x00,0x00],
ShowCommand = [0x01,0x00,0x00,0x00], //SW_SHOWNORMAL
Hotkey = [0x00,0x00], // No Hotkey
Reserved = [0x00,0x00],
Reserved2 = [0x00,0x00,0x00,0x00],
Reserved3 = [0x00,0x00,0x00,0x00],
TerminalID = [0x00,0x00],
CLSID_Computer = convert_CLSID_to_DATA("20d04fe0-3aea-1069-a2d8-08002b30309d"),
CLSID_Network = convert_CLSID_to_DATA("208d2c60-3aea-1069-a2d7-08002b30309d"),
PREFIX_LOCAL_ROOT = [0x2f],
PREFIX_FOLDER = [0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
PREFIX_FILE = [0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
PREFIX_NETWORK_ROOT = [0xc3,0x01,0x81],
PREFIX_NETWORK_PRINTER = [0xc3,0x02,0xc1],
END_OF_STRING = [0x00];
if (/.*\\+$/.test(lnk_target)) {
lnk_target = lnk_target.replace(/\\+$/g, '');
var target_is_folder = true;
}
var prefix_root, item_data, target_root, target_leaf;
if (lnk_target.substr(0, 2) === '\\\\') {
prefix_root = PREFIX_NETWORK_ROOT;
item_data = [0x1f, 0x58].concat(CLSID_Network);
target_root = lnk_target.subtr(lnk_target.lastIndexOf('\\'));
if (/\\\\.*\\.*/.test(lnk_target)) {
target_leaf = lnk_target.substr(lnk_target.lastIndexOf('\\') + 1);
}
if (target_root === '\\') {
target_root = lnk_target;
}
} else {
prefix_root = PREFIX_LOCAL_ROOT;
item_data = [0x1f, 0x50].concat(CLSID_Computer);
target_root = lnk_target.replace(/\\.*$/, '\\');
if (/.*\\.*/.test(lnk_target)) {
target_leaf = lnk_target.replace(/^.*?\\/, '');
}
}
var prefix_of_target, file_attributes;
if (!target_is_folder) {
prefix_of_target = PREFIX_FILE;
file_attributes = FileAttributes_File;
} else {
prefix_of_target = PREFIX_FOLDER;
file_attributes = FileAttributes_Directory;
}
target_root = str_to_arr(target_root);
for (var i = 1; i <= 21; ++i) {
target_root.push(0);
}
var id_list_items = gen_IDLIST(item_data);
id_list_items = id_list_items.concat(
gen_IDLIST(prefix_root.concat(target_root, END_OF_STRING)));
if (target_leaf) {
target_leaf = str_to_arr(target_leaf);
id_list_items = id_list_items.concat(
gen_IDLIST(prefix_of_target.concat(target_leaf, END_OF_STRING)));
}
var id_list = gen_IDLIST(id_list_items);
var data = [].concat(HeaderSize,
LinkCLSID,
LinkFlags,
file_attributes,
CreationTime,
AccessTime,
WriteTime,
FileSize,
IconIndex,
ShowCommand,
Hotkey,
Reserved,
Reserved2,
Reserved3,
id_list,
TerminalID);
return new Blob([new Uint8Array(data)], { type: 'application/x-ms-shortcut' });
}
var blob = create_lnk_blob('C:\\Windows\\System32\\Calc.exe');
Use it like:
var blob_to_file = create_lnk_blob('C:\\Windows\\System32\\Calc.exe');
var blob_to_folder = create_lnk_blob('C:\\Users\\Myself\\Desktop\\'); // with a trailing slash
Demo: http://jsfiddle.net/5cjgLyan/2/

This would be simple if your website allows php.
If your script is part of an html file, just write the the javascript as if you were writing it to send a static lnk file. Then, at the lnk address part, break apart the javascript into two parts, breaking into html. Then at that point, put in
<?php /*PHP code set a variable *? /* PHP code to generate proper string*/ PRINT /*PHP variable*/
?>

I think make it pure client is impossible.
Even the web rtc protocol need at least one iceServer to signal other client.
And I think the easiest way to do that is use http://peerjs.com/
you could first create a clinet token of the room owner
//room owner side
peer.on('open', function(my_peer_id) {
console.log('My peer ID is: ' + my_peer_id);
});
And send the token to any other you want (by text file, web chat ...etc)
Then other connect it use the token above
//the other one
var conn = peer.connect(other_peer_id);
After the room owner detected someone entered the room.
Disconnect from signal server, so the token will become unusable
//room owner side
peer.disconnect()
About generate and read file by client side, I recommend you read article below.
http://www.html5rocks.com/en/tutorials/file/dndfiles/ read from file
How to use filesaver.js save as file
I believe the compatibility of fileReader api and blob doesn't matter.
Since there will never be a browser which support webrtc but not support fileReader api

Related

GAS how upload multiple file in google drive

I'm trying to upload multiple files into Google Drive Using Google Apps Script.
My code work fine when I want to upload one file
// UPLOAD IMG IN GOOGLE DRIVE
var url = 'http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png';
var response = UrlFetchApp.fetch(url); // get api endpoint
var rc = response.getResponseCode();
if(rc=200){
var fileBlob = response.getBlob();
var folder = DriveApp.getFolderById("xxxxxx")
if(folder !=null) {
var file_img = folder.createFile(fileBlob)
var img = file_img.getUrl();
}
}
} else {
var img = "";
}
// APPEND VALUE TO SHEET
sheet.appendRow([img]);
I'm trying to modify the above script in order to upload multiple files into google drive, but my code doesn't works.
This is my (not working) code:
// UPLOAD IMG IN GOOGLE DRIVE
var url = ['http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png', 'https://www.yourcloudworks.com/wp-content/uploads/2019/09/number-digit-2-png-transparent-images-transparent-backgrounds-Number-2-PNG-images-free-download_PNG14949.png'];
for(var i=0; i<url.length; i++){
var response = UrlFetchApp.fetchAll(url);
var rc = response.getResponseCode();
if(rc=200){
var fileBlob = response.getBlob();
var folder = DriveApp.getFolderById("xxxxxx")
if(folder !=null) {
var file_img = folder.createFile(fileBlob[i])
var img = file_img.getUrl()[i];
}
}
} else {
var img = "";
}
// APPEND VALUE TO SHEET
sheet.appendRow(img[i]);
}
TypeError: response.getResponseCode is not a function
Any help?
Modification points:
In your script, for(var i=0; i<url.length; i++){}else{} is used. I thought that you might misunderstand the if statement and for loop.
When you want to compare the value at the if statement, please modify if(rc=200){ to if(rc==200){.
The response value from UrlFetchApp.fetchAll(url) is an array.
I think that the reason of the error message is this.
folder.createFile(fileBlob[i]) is folder.createFile(fileBlob).
file_img.getUrl()[i] is file_img.getUrl().
When file_img.setTrashed(true) is used, the downloaded files are moved to the trashbox. If you don't want to move them to the trashbox, please remove the line.
I think that when the values are put to the Spreadsheet by one request, the process cost will be low. In your script, I would like to propose to use setValues instead of appendRow.
When above points are reflected to your script, it becomes as follows.
Modified script:
Please copy and paste the following modified script. And please set the variable of sheet, and the folder ID.
function myFunction() {
// var sheet = SpreadsheetApp.getActiveSheet();
var url = ['http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png', 'https://www.yourcloudworks.com/wp-content/uploads/2019/09/number-digit-2-png-transparent-images-transparent-backgrounds-Number-2-PNG-images-free-download_PNG14949.png'];
var requests = url.map(u => ({url: u, muteHttpExceptions: true}));
var response = UrlFetchApp.fetchAll(requests);
var imgs = [];
for (var i = 0; i < response.length; i++) {
if (response[i].getResponseCode() == 200) {
var fileBlob = response[i].getBlob();
var folder = DriveApp.getFolderById("xxxxxx");
if (folder != null) {
var file_img = folder.createFile(fileBlob);
imgs.push([file_img.getUrl()]);
// file_img.setTrashed(true); // When this script is used, the downloaded files are moved to the trashbox.
}
}
}
if (imgs.length > 0) {
sheet.getRange(sheet.getLastRow() + 1, 1, imgs.length).setValues(imgs);
}
}
When muteHttpExceptions: true is used, the script can be run even when an error occurs.
References:
fetchAll(requests)
if...else
Loops and iteration

Is there a JavaScript InDesign function to get ID value

I used the command to export the hard drive ID to drive C:
var command="wmic diskdrive get SerialNumber > C:/idhdd.txt";
app.system("cmd.exe /c\""+command+"" );
I get the text file
SerialNumber
2012062914345300
Is there a JavaScript statement to remove SerialNumber, I just want to get the ID in the text file and save it to the hard drive C.
Here's ready-to-use getDriveIDs() function that should work in any Adobe app and will return array of HDD ID strings for you. I hope this can be easily generalized for other scenarios with Windows scripting inside Adobe scripting ;-)
//----------------------------------------------------------------------//
// Detects IDs (serial numbers) of connected drives and returns them as array of strings.
var getDriveIDs = function() {
var idFile = File(Folder.temp + '/saved_hdd_serials.txt');
var scriptFile = File(Folder.temp + '/dump_hdd_serials.bat');
var scriptContent = 'wmic diskdrive get SerialNumber > ' + idFile.fsName + '\n';
var ids = []
withTempFile(scriptFile, scriptContent, function() {
scriptFile.execute();
$.writeln(idFile.length == 0); // wait for asynchronous script execution to finish
$.sleep(1);
withTempFile(idFile, undefined, function(file, lines) {
ids = lines.slice(1);
});
});
return ids;
};
//----------------------------------------------------------------------//
// utilities
var withTempFile = function(file, content, callback) {
if (undefined == content) { // read temp file
file.open('r');
content = [];
while (!file.eof)
content.push(file.readln());
} else { // write temp file
file.open('w');
file.write(content);
content = undefined;
}
file.close();
callback(file, content);
file.remove();
}
//----------------------------------------------------------------------//
// main: demo
var ids = getDriveIDs();
alert('Drive IDs:\n\t' + ids.join('\n\t'));

Session.Create(FlowFile) Transfers with no content

I am trying to build a Excecute Script Processor for Nifi.
It handles a JSON file, splits it and sends it to the next processor, which is an MongoDB writer.
The logic works so far. The main problem is, that I cannot get the processor to create and send a new FlowFile for each new JSON created out of the input JSON. I got it working a bit but unfortunately, all the FlowFiles come out empty. Is there something wrong with the flow (from creation of a new Flow to sending it)?
Here is a code snippet:
var flowFile = session.get();
if (flowFile != null) {
var StreamCallback = Java.type("org.apache.nifi.processor.io.StreamCallback");
var IOUtils = Java.type("org.apache.commons.io.IOUtils");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
try {
flowFile = session.write(flowFile,
new StreamCallback(function (inputStream, outputStream) {
var content = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
var json = JSON.parse(content);
var events = json["events"];
var mongoEvent = "";
var flowFileList = [];
for(var x = 0; x < json["events"].length; x++){
try{
var newFlowFile = session.create();
mongoEvent = constructJSONEvent(x, json); // Here we will receive our new JSON
outputStream.write(mongoEvent.getBytes(StandardCharsets.UTF_8));
session.transfer(newFlowFile, REL_SUCCESS);
}catch(e){
session.transfer(newFlowFile, REL_FAILURE);
}
}
}));
session.transfer(flowFile, REL_SUCCESS);
} catch(e) {
session.transfer(flowFile, REL_FAILURE);
}
}

Google Drive + Script throws permissions error even through I'm owner and granted permission

I'm trying to create a basic script on a 12-hour timer trigger that loops through each of my Google Calendars by their ICAL URL, and downloads the ICAL for a folder on my Google Drive (for backup purposes). It throws this error
"No item with the given ID could be found, or you do not have permission to access it. (line 23, file "Code")" (Line #23 is var folder... )
Running the script does download and save the ICAL file on the first run through the loop (and if I manually pass in each unique ICAL URL one at a time), but the error then terminates the loop. Seeing as how I've authorized access already and am the owner of everything here, I'm not sure what else I need.
var calendarsToSave = [
"https://calendar.google.com/calendar/ical/inXXXXXXX.com/privateXXXX/basic.ics",
"https://calendar.google.com/calendar/ical/XXXXX.com_XXXXXXup.calendar.google.com/private-XXXXXXX/basic.ics"
];
var folder = '123xxxxxxxxv789'; // my gdrive folder
function downloadFile(calendarURL,folder) {
var fileName = "";
var fileSize = 0;
for (var i = 0; i < calendarsToSave.length; i++) {
var calendarURL = calendarsToSave[i];
var response = UrlFetchApp.fetch(calendarURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var folder = DriveApp.getFolderById(folder); // << returns a permissions error thus terminating the for loop
var file = folder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
} // end for loop
}
Updated: You are also re-initializing a variable that already exists from the parameters and as a global variable so we can remove the parameter if you want to keep the global variable.
We can also move the place where you get the Google Folder object. It stays the same every time so we don't need to retrieve it again.
var calendarsToSave = [
"https://calendar.google.com/calendar/ical/inXXXXXXX.com/privateXXXX/basic.ics",
"https://calendar.google.com/calendar/ical/XXXXX.com_XXXXXXup.calendar.google.com/private-XXXXXXX/basic.ics"
];
var folder = '123xxxxxxxxv789'; // my gdrive folder
function downloadFile(calendarURL) {
var fileName = "";
var fileSize = 0;
var gfolder = DriveApp.getFolderById(folder);
for (var i = 0; i < calendarsToSave.length; i++) {
var calendarURL = calendarsToSave[i];
var response = UrlFetchApp.fetch(calendarURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var file = gfolder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
} // end for loop
}
Let see where that gets us.
Your "folder" variable is outside the function, causing the data to be inaccessible to the "downloadFile" function.
Google apps coding seems to require variables to be in a function to be defined. I would recommend moving both "calendarsToSave" and "folder" to the inside of "downloadFile"
Here is an example that will return your error:
var folder = '1HSFBPfPIsXWvFEb_AalFYalkPwrOAyxD';
function myFunction() {
var folder = DriveApp.getFolderById(folder);
var name = folder.getName();
Logger.log(name);
}
And here is one that will return the file name:
function myFunction() {
var folder = '1HSFBPfPIsXWvFEb_AalFYalkPwrOAyxD';
var folder = DriveApp.getFolderById(folder);
var name = folder.getName();
Logger.log(name);
}

createFile() in google Apps Script is not functioning properly

I am trying to create a file. It works fine when I run the following code segment from the debugger in apps script. However, when I run it real time from the spreadsheet, it says I do not have permission to call createfile. Everything that is logged is identical. The issue is not I do not have authority as I am the only one in the spreadsheet and am the owner. The purpose of the CSV is to move it from my google drive into data for BigQuery
function saveAsCSV(row) { //Doc to Csv
//row = 3; //when this is uncommented and ran from the debugger, it works.
try{
var fileName= Date.now()
fileName = fileName + ".csv";
var csvFile = convertRangeToCsvFile_(fileName,row);
Logger.log(csvFile); //Both times ran on the spreadsheet and from debug equals the same.
DriveApp.createFile(fileName, csvFile);
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("New and Open").getRange("J" + row.toString()).setValue("");
loadCsv(fileName);
}
catch(e){Logger.log("B" + e.message);} //No permission to create file
}
function convertRangeToCsvFile_(csvFileName, r) {
var ws = SpreadsheetApp.getActiveSpreadsheet();
try {
//var data = ws.getValues();
var csvFile = undefined;
var csv = "";
var row = r;
var datArray = Create2DArray(1,19);
datArray[0][0] = ws.getRange("A" + row.toString()).getValue().toString().toUpperCase();
datArray[0][1] = ws.getRange("B"+row.toString()).getValue().toString().toUpperCase();
datArray[0][2] = ws.getRange("C"+row.toString()).getValue().toString().toUpperCase();
datArray[0][3] = ws.getRange("D"+row.toString()).getValue().toString().toUpperCase();
datArray[0][4] = ws.getRange("E"+row.toString()).getValue().toString().toUpperCase();
datArray[0][5] = ws.getRange("F"+row.toString()).getValue().toString().toUpperCase();
datArray[0][6] = ws.getRange("G"+row.toString()).getValue().toString().toUpperCase();
datArray[0][7] = ws.getRange("H"+row.toString()).getValue().toString().toUpperCase();
datArray[0][8] = ws.getRange("I"+row.toString()).getValue().toString().toUpperCase();
datArray[0][9] = new Date(ws.getRange("K"+row.toString()).getValue().toString()).getHours();
datArray[0][10] = new Date(ws.getRange("K"+row.toString()).getValue().toString()).getMinutes();
datArray[0][11] = new Date(ws.getRange("L"+row.toString()).getValue().toString()).getHours();
datArray[0][12] = new Date(ws.getRange("L"+row.toString()).getValue().toString()).getMinutes();
datArray[0][13] = new Date(ws.getRange("M"+row.toString()).getValue().toString()).getHours();
datArray[0][14] = new Date(ws.getRange("M"+row.toString()).getValue().toString()).getMinutes();
datArray[0][15] = new Date(ws.getRange("N"+row.toString()).getValue().toString()).getTime();
datArray[0][16] = new Date(ws.getRange("N"+row.toString()).getValue().toString()).getFullYear();
datArray[0][17] = new Date(ws.getRange("N"+row.toString()).getValue().toString()).getMonth();
datArray[0][18] = new Date(ws.getRange("N"+row.toString()).getValue().toString()).getDate();
for(var i = 0; i < 19; i++){
if(datArray[0][i] == ""){if(i > 9){datArray[0][i] = 0;} else{datArray[0][i] = "nil";} }
if(i < 18){csv += '"' + datArray[0][i] + '"' + ",";}
else{ csv += '"' + datArray[0][i] + '"'; }
}
Logger.log("A " + csv);
Logger.log(csv + "\n" + datArray[0].join(","));
csvFile = csv;
return csvFile;
}
catch(err) {
Logger.log("C" + err);
Browser.msgBox(err);
}
}
You mention in your comment on my answer that you are using onEdit to trigger the script. Since this is a Simple Trigger, your current approach will not work. When you use simple triggers to run an Apps Script, it runs in a sandbox with reduced permissions.
See: https://developers.google.com/apps-script/guides/triggers/#restrictions
The best I can recommend is create a custom menu option with a UI popup asking for the row number to export. If the code is triggered from a menu by the user, it runs with full permission to access that users account.
Depending on your use-case, a scheduled trigger might work too. It could run every 10 minutes or every Hour and export any changes to the spreadsheet. In this case the Apps Script runs as you, with permission to access your account, and the resulting CSV would be created on your drive.
Details on how to create a custom menu: https://developers.google.com/apps-script/guides/triggers/#onopen
Details on how to create a form for the user: https://developers.google.com/apps-script/guides/ui-service
Details on time driven triggers: https://developers.google.com/apps-script/guides/triggers/installable#time-driven_triggers

Categories

Resources