VSCode: Decrypt on open, encrypt on save - encryption

The file i want to open has a simple encryption (it is from a software, but i have the license to encrypt it). If I open it as plain text it is not human readable.
For simplicity just assume, that every char is shifted by one bit.
I want to change that, if the extension is right.
Openinig should decrypt the file, so it can be edited.
Closing should encrypt it again, so the program reading the file is able to do so.
I have the logic running as a Notepad++ plugin, but I do not know how to implement it in VSCode.
Currently a language server is setup running for the decrypted files. This seems to work fine.
Can I implement the logic anywhere in it, without to much performance penalty?

You can use the onDidOpenTextDocument and onDidChangeActiveTextEditor events to run code when the text editor has been changed to a newly opened file. Then in the onDidChangeActiveTextEditor event, read the contents of the document, run the decrypt function, then use the TextEditor.edit function to replace the text with decrypt text.
To encrypt after the file has been saved, use the onDidSaveTextDocument function to read the saved file, encrypt the contents, then write the encrypted text to the saved file.
import * as vscode from 'vscode';
import * as path from 'path';
let steveChannel: vscode.OutputChannel | undefined;
let lastOpenFile = '' ;
// ----------------------------------- activate -----------------------------------
export function activate(context: vscode.ExtensionContext)
{
steveChannel_writeLine(`activate`);
vscode.window.onDidChangeActiveTextEditor((editor) =>
{
// text editor has been changed to a newly opened text file.
if ( lastOpenFile == editor?.document.fileName )
{
let document = editor.document;
const doc_text = editor.document.getText();
const uc_text = doc_text.toUpperCase();
// update contents of text editor to uppercase text.
editor.edit(editBuilder =>
{
const range = doc_entireDocRange(document) ;
editBuilder.replace( range, uc_text);
});
}
});
vscode.workspace.onDidOpenTextDocument((d) =>
{
const ext = path.extname(d.fileName) ;
if ( ext == '.txt')
{
steveChannel_writeLine(`file opened ${d.fileName}`);
// save name of most recently opened .txt file.
// Use in change text editor event to detect when the text editor
// contains the contents of a newly opened text file.
lastOpenFile = d.fileName ;
}
});
vscode.workspace.onDidSaveTextDocument((d) =>
{
const ext = path.extname(d.fileName);
if (ext == '.txt')
{
steveChannel_writeLine(`file saved ${d.fileName}`);
}
});
}
// ---------------------------------- deactivate ----------------------------------
// this method is called when your extension is deactivated
export function deactivate() {}
// ---------------------------- steveChannel_writeLine ----------------------------
function steveChannel_writeLine(line: string)
{
if (!steveChannel)
{
steveChannel = vscode.window.createOutputChannel('steve');
}
steveChannel.appendLine(line);
}
// ----------------------------- doc_entireDocRange -----------------------------
function doc_entireDocRange( doc: vscode.TextDocument )
{
let invalidRange = new vscode.Range(0, 0, doc.lineCount /*intentionally missing the '-1' */, 0);
let docRange = doc.validateRange(invalidRange);
return docRange ;
}

Related

Uploading an image to Firestore. How to read file format before upload

I'm using the expo-image-picker to select an image and then upload it to FireStore
const pickImage=async()=>{
let result=await ImagePicker.launchImageLibraryAsync({
mediaTypes:ImagePicker.MediaTypeOptions.Images,
allowsEditing:true,
aspect:[4,3],
quality:1,
});
if (!result.cancelled){
setSelectedImage(result.uri)
}
}
let Enter = async () => {
const storage=getStorage();
const reference=ref(storage,title+'.png')
const img=await fetch(selectedImage);
const bytes=await img.blob();
await uploadBytes(reference,bytes);
await createEntry(title,descr);
};
The 'pickImage' function lets me pick the image from the computer, the 'Enter' function uploads it, then 'CreateEntry' just creates a seperate document which references the stored image.
Everything works fine except when I declare the reference constant under 'Enter'. If I don't include "+'.png'" after title it just shows up as a text document in Firestore. "+'.png'" is a workaround but obviously this limits me to just uploading pngs. I would like to create a 'documentFormat' variable which I could just add in there so it would look like:
const reference=ref(storage,title+documentFormat) but I can't figure out how to read the format of the selected document.
The ImagePicker.launchImageLibraryAsync method does not return a mime type for the selected file. What you can do is use this helper function to get the file extension and accordingly use it in place.
function get_extension(url: string) {
let extension = url.toLowerCase().split(".").pop();
return extension; // png, mp4, jpeg etc.
}
Usage
const reference = ref(storage, title + get_extension(selectedImage))

Issues with Paw's DynamicValueInput type JSON and Checkbox

I want to create a DynamicValue plugin for Paw generating Json Web Tokens. The full source can be found here: https://github.com/choffmeister/Paw-JsonWebTokenDynamicValue
Relevant file:
// JsonWebTokenDynamicValue.js
import jsrsasign from 'jsrsasign';
#registerDynamicValueClass
class JsonWebTokenDynamicValue {
static identifier = 'de.choffmeister.PawExtensions.JsonWebTokenDynamicValue';
static title = 'Json Web Token';
static help = 'https://github.com/choffmeister/Paw-JsonWebTokenDynamicValue';
static inputs = [
DynamicValueInput('signatureSecret', 'Secret', 'SecureValue'),
DynamicValueInput('signatureSecretIsBase64', 'Secret is Base64', 'Checkbox'),
DynamicValueInput('payload', 'Payload', 'JSON')
];
evaluate() {
console.log(JSON.stringify(this.payload, null, 2));
console.log(JSON.stringify(this.signatureSecretIsBase64, null, 2));
const now = Math.floor((new Date()).getTime() / 1000);
const header = {
typ: 'JWT',
alg: 'HS256'
};
const payload = {
...this.payload,
exp: now + (60 * 60 * 24 * 7),
iat: now
};
const secret = this.signatureSecretIsBase64
? {b64: jsrsasign.b64utob64(this.signatureSecret)}
: this.signatureSecret;
return jsrsasign.jws.JWS.sign(null, header, payload, secret);
}
}
How it looks in the GUI:
I searched https://luckymarmot.com/paw/doc/extensions/create-dynamic-value, the surrounding documentation and all plugin examples I could find on the web, but I still have two problems I cannot solve:
When using the DynamicValueInput of type Checkbox then the input field is not visible (see screenshot). I get a value (empty string), but just cannot see it. How can I make the checkbox appear?
When using the DynamicValueInput of type JSON then used dynamic values inside the JSON (see screenshot) are not resolved, but instead I get kind of a description object (stringified), what this dynamic value is. Logging the this.payload object looks like this:
{
"foo": "[{\"data\":{\"environmentVariable\":\"2925ABDA-8AAC-440B-B2CA-DA216CD37A09\"},\"identifier\":\"com.luckymarmot.EnvironmentVariableDynamicValue\"}]"
}
Maybe it is worth to note: When using DynamicInputValue of type KeyValueList then the inner dynamic values are resolved properly. How can I achive this with the JSON type, too?
This issue has been solved in Paw 2.3.3 and #Thekwasti's extension has actually been published here: https://luckymarmot.com/paw/extensions/JsonWebTokenDynamicValue

Trouble reading sqlite3 database columns of type blob with sql.js

So i am using the sql.js library i.e. the port of sqlite in javascript which can be found here https://github.com/kripken/sql.js.
This is my code to open and read the database that comes from a flat file store locally.
First the file a local file is selected via this HTML
<input type="file" id="input" onchange="handleFiles(this.files)">
The js code behind the scenes is as follows,
function handleFiles(files) {
var file = files[0];
var reader = new FileReader();
reader.readAsBinaryString(file);
openDbOnFileLoad(reader);
function openDbOnFileLoad(reader){
setTimeout(function () {
if(reader.readyState == reader.DONE) {
//console.log(reader.result);
db = SQL.open(bin2Array(reader.result));
execute("SELECT * FROM table");
} else {
//console.log("Waiting for loading...");
openDbOnFileLoad(reader);
}
}, 500);
}
}
function execute(commands) {
commands = commands.replace(/\n/g, '; ');
try {
var data = db.exec(commands);
console.log(data);
} catch(e) {
console.log(e);
}
}
function bin2Array(bin) {
'use strict';
var i, size = bin.length, ary = [];
for (i = 0; i < size; i++) {
ary.push(bin.charCodeAt(i) & 0xFF);
}
return ary;
}
Now this works and i can access all the columns and values in the database, however there is one column which is of type blob and that just shows up as empty. Any ideas of how i can access the contents of this blob?
The correct answer!
So what I was trying to ask in this question is simply how to read the contents of a column of type blob using sql.js. The correct answer is to specify the column names in the question and for the column that contains data of type blob, get its contents using the hex function i.e. select column1,hex(column2) from table. It was by no means a question about the most efficient way of doing this. I have also written a blog post about this.
Here is a slightly modified copy of the function responsible for initializing my sqlite database:
sqlite.prototype._initQueryDb = function(file, callback) {
self = this;
var reader = new FileReader();
// Fires when the file blob is done loading to memory.
reader.onload = function(event) {
var arrayBuffer = event.target.result,
eightBitArray = new Uint8Array(arrayBuffer),
database = SQL.open(eightBitArray);
self._queryDb = database;
// Trigger the callback to the calling function
callback();
}
// Start reading the file blob.
reader.readAsArrayBuffer(file);
}
In this case, file is a local sqlite database handle that I get from an HTML input element. I specify a function to call when a change event happens to that input and get the blob from the resulting event.target.files[0] object.
For the sake of brevity on my part I left some things out but I can throw together a smaller and more simplified example if you are still struggling.
The answer is: with kripken's sql.js, that you mentioned above you can't. At least as of today (may 2014). The original author doesn't maintain sql.js anymore.
However, I'm the author of a fork of sql.js, that is available here: https://github.com/lovasoa/sql.js .
This fork brings several improvements, including support for prepared statements, in which, contrarily to the original version, values are handled in their natural javascript type, and not only as strings.
With this version, you can handle BLOBs (both for reading and writing), they appear as Uint8Arrays (that you can for instance convert to object URL to display contents to your users).
Here is an example of how to read blob data from a database:
var db = new SQL.Database(eightBitArray); // eightBitArray can be an Uint8Array
var stmt = db.prepare("SELECT blob_column FROM your_table");
while (stmt.step()) { // Executed once for every row of result
var my_blob = stmt.get()[0]; // Get the first column of result
//my_blob is now an Uint8Array, do whatever you want with it
}
db.close(); // Free the memory used by the database
You can see the full documentation here: http://lovasoa.github.io/sql.js/documentation/

CollectionFS error - Uncaught Error: CollectionFS: file.slice not supported?

I've been getting the above error when attempting to insert a photo into the database. What's weird is that the file side of the document is inserted fine, but nothing gets inserted to the chunk side. I looked around the web but didn't get any hints as to what the problem may be. Has anybody seen this error and can help?
Here's my code.
collections.js
PhotosFS = new CollectionFS('photos');
PhotosFS.allow({
insert: function (userId, file) {
return userId && file.owner === userId;
}
});
events.js
Template.createPhotos.events({
"change input[type='file']": function (e, tmpl) {
var file = e.target.files;
Session.set('currentFile', file[0]);
},
"click .save-button": function (e, tmpl) {
var file = Session.get('currentFile');
PhotosFS.storeFile(file, {
name: name,
photographer: photographer,
caption: caption,
});
}
});
I'm guessing it has something to do with storing the file in a session before uploading to the database because if you directly upload the file after a change on the input file it uploads fine. When it is uploaded direct from the input file change event, it uploads as a file. But when it is stored in a session then uploaded, it's uploaded as an object. I guess the CollectionFS chunks don't recognize objects. I don't know. But I do know that for my particular app having the files uploaded directly after the input file change event doesn't make sense.
But I guess I'll have to do this
Template.createPhotos.events({
"change input[type='file']": function (e, template) {
var file = e.target.files;
var fileId = PhotosFS.storeFile(file[0]);
Session.set('currentFile', fileId)
},
"click .save-button": function (e, tmpl) {
var file = Session.get('currentFile');
PhotosFS.storeFile(file, {$set: {
name: name,
photographer: photographer,
caption: caption,
}});
}
});
I won't accept my own answer because I'm still hoping for someone to find a way to work with storing the file in a session before uploading.

Capture photo with camera and store in DB Phonegap

I am trying to build an app using Phonegap (Cordova 2.2). I am fairly new to code and js in particular so please be patient if some of my questions seem daft. My question has a few parts:
I want the user to be able to enter name and image (using the device camera) to create their profile. I have tested on the emulator and so far they can enter their name and get take a photo with camera. These both display in the emulator on completion. However, obviously I want to save that detail, so, I have created a DB (from reading, local storage is limited in size).
1. Is the database done correctly? I am getting neither error nor success alerts.
2. I am struggling with the logic of how I pass the information into the database. I'm guessing that I call the populate_UsersDB() function on a click event and need to write some sort of INSERT INTO userProfiles VALUE something. Also, can I grab the Imagedata directly from the onPhotoFileSuccess() function and send it into the database from there.
3. If I don't want to have a done button (rather have a 'Tap here to take picture' placeholder), how do I test that the action is complete and send the info to the db. From reading, I think I can use onChange(), but not sure. Also, guessing I have to use post or get somewhere?
Sorry, I know there is a lot of questions within this question. Any advice or support is greatly appreciated. Thanks. Here's the code.
//Use the device camera to capture an image of the user
var pictureSource; // picture source
var destinationType; // sets the format of returned value
// Wait for PhoneGap to connect with the device
document.addEventListener("deviceready",onDeviceReady,false);
// PhoneGap is ready to be used!
function onDeviceReady() {
pictureSource=navigator.camera.PictureSourceType;
destinationType=navigator.camera.DestinationType;
}
// Called when a photo is successfully retrieved
function onPhotoDataSuccess(imageData) {
// Get image handle
var smallImage = document.getElementById('smallImage');
// Unhide image elements
//
smallImage.style.display = 'block';
// Show the captured photo
// The inline CSS rules are used to resize the image
//
smallImage.src = "data:image/jpeg;base64," + imageData;
}
// Called when a photo is successfully retrieved
function onPhotoFileSuccess(imageData) {
// Get image handle
console.log(JSON.stringify(imageData));
// Get image handle
//
var smallImage = document.getElementById('smallImage');
// Unhide image elements
//
smallImage.style.display = 'block';
// Show the captured photo
// The inline CSS rules are used to resize the image
//
smallImage.src = imageData;
}
// A button will call this function
function capturePhotoWithData() {
// Take picture using device camera and retrieve image as base64-encoded string
navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality:50, destinationType:Camera.DestinationType.DATA_URL });
}
function getPhoto(source) {
// Retrieve image file location from specified source
navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 50,
destinationType: destinationType.FILE_URI,
sourceType: source });
}
// Called if something goes wrong.
function onFail(message) {
alert('Failed because: ' + message);
}
//CREATE THE DATABASE
document.addEventListener("deviceready", onDeviceReady, false);
var db = window.openDatabase("Users_DB", "1.0", "User Profiles DB", 200000); //will create database or open it
//function will be called when device ready
function onDeviceReady(){
db.transaction(populateUsers_DB, errorCB, successCB);
}
//create table
function populateUsers_DB(tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS userProfiles (id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT NOT NULL, Image BLOB)');
tx.executeSql('INSERT INTO userProfiles(Name) VALUE ("")');
}
//function will be called when an error occurred
function errorCB(err) {
alert("Error processing SQL: "+err.code);
}
//function will be called when process succeed
function successCB() {
alert("success!");
db.transaction(queryDB,errorCB);
}
//select all from userProfiles
function queryDB(tx){
tx.executeSql('SELECT * FROM userProfiles',[],querySuccess,errorCB);
}
function querySuccess(tx,result){
$('#userList').empty();
$.each(result.rows,function(index){
var row = result.rows.item(index);
$('#userList').append('<li><h3 class="ui-li-heading">'+row['Image']+'</h3><p class="ui-li-desc">Name '+row['Name']+'</p></li>');
});
$('#userList').listview();
}

Resources