Skip to content

Commit

Permalink
#24 Add option to document encrypt to not encrypt to the caller of th…
Browse files Browse the repository at this point in the history
…e SDK
  • Loading branch information
Ernie Turner committed Feb 19, 2020
1 parent 1cc23ca commit 00fe73f
Show file tree
Hide file tree
Showing 10 changed files with 1,808 additions and 1,447 deletions.
52 changes: 38 additions & 14 deletions integration/Documents.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from "fs";
import * as inquirer from "inquirer";
import fetch from "node-fetch";
import * as path from "path";
import * as request from "request";
import {SDK} from "../ironnode";
import {log} from "./Logger";

Expand Down Expand Up @@ -29,6 +29,12 @@ const sharedDocumentQuestions: inquirer.Question[] = [
type: "input",
message: "Comma separated list of groups to grant access:",
},
{
name: "grantToAuthor",
type: "confirm",
message: "Encrypt document to current user?",
default: true,
},
];

/**
Expand Down Expand Up @@ -101,22 +107,23 @@ function getFormattedDocumentList(IronNode: SDK) {
*/
function encryptDirectInput(IronNode: SDK) {
return inquirer
.prompt<{data: string; id: string; name: string; userShares: string; groupShares: string}>([
.prompt<{data: string; id: string; name: string; userShares: string; groupShares: string; grantToAuthor: boolean}>([
{
name: "data",
type: "input",
message: "Todo items (comma seperate multiple items):",
},
...sharedDocumentQuestions,
])
.then(({id, name, data, userShares, groupShares}) => {
.then(({id, name, data, userShares, groupShares, grantToAuthor}) => {
const options = {
documentID: id || undefined,
documentName: name || undefined,
accessList: {
users: idListToAccessList(userShares),
groups: idListToAccessList(groupShares),
},
grantToAuthor,
};
const docData = {
type: "list",
Expand Down Expand Up @@ -176,7 +183,7 @@ function decryptDirectInput(IronNode: SDK, documentID: string) {
*/
function encryptUrl(IronNode: SDK) {
return inquirer
.prompt<{url: string; outputFile: string; id: string; name: string; userShares: string; groupShares: string}>([
.prompt<{url: string; outputFile: string; id: string; name: string; userShares: string; groupShares: string; grantToAuthor: boolean}>([
{
name: "url",
type: "input",
Expand All @@ -191,18 +198,21 @@ function encryptUrl(IronNode: SDK) {
},
...sharedDocumentQuestions,
])
.then(({url, outputFile, id, name, userShares, groupShares}) => {
.then(({url, outputFile, id, name, userShares, groupShares, grantToAuthor}) => {
const options = {
documentID: id || undefined,
documentName: name || undefined,
accessList: {
users: idListToAccessList(userShares),
groups: idListToAccessList(groupShares),
},
grantToAuthor,
};
return IronNode.document
.encryptStream(request.get(url) as any, fs.createWriteStream(outputFile), options)
.then((encryptedDocument) => ({encryptedDocument, outputFile}));
return fetch(url).then((response) =>
IronNode.document
.encryptStream(response.body, fs.createWriteStream(outputFile), options)
.then((encryptedDocument) => ({encryptedDocument, outputFile}))
);
})
.then(({encryptedDocument, outputFile}) => {
log({
Expand All @@ -217,18 +227,19 @@ function encryptUrl(IronNode: SDK) {
*/
function encryptFile(IronNode: SDK) {
return inquirer
.prompt<{inputFile: string; outputFile: string; id: string; name: string; userShares: string; groupShares: string}>([
.prompt<{inputFile: string; outputFile: string; id: string; name: string; userShares: string; groupShares: string; grantToAuthor: boolean}>([
...getFormattedFilePathQuestions("Provide the path to the file to encrypt:", "Provide the path of where to write the output:"),
...sharedDocumentQuestions,
])
.then(({id, name, inputFile, outputFile, userShares, groupShares}) => {
.then(({id, name, inputFile, outputFile, userShares, groupShares, grantToAuthor}) => {
const options = {
documentID: id || undefined,
documentName: name || undefined,
accessList: {
users: idListToAccessList(userShares),
groups: idListToAccessList(groupShares),
},
grantToAuthor,
};
return IronNode.document
.encryptStream(fs.createReadStream(inputFile), fs.createWriteStream(outputFile), options)
Expand Down Expand Up @@ -310,7 +321,10 @@ export function parseID(IronNode: SDK) {
name: "docType",
type: "list",
message: "What type of document are we parsing?",
choices: [{name: "Direct Input", value: "direct"}, {name: "File", value: "file"}],
choices: [
{name: "Direct Input", value: "direct"},
{name: "File", value: "file"},
],
})
.then(({docType}) => {
if (docType === "file") {
Expand Down Expand Up @@ -350,7 +364,11 @@ export function encryptDocument(IronNode: SDK) {
name: "docType",
type: "list",
message: "What type of document are you encrypting?",
choices: [{name: "Direct Input", value: "direct"}, {name: "File", value: "file"}, {name: "URL", value: "url"}],
choices: [
{name: "Direct Input", value: "direct"},
{name: "File", value: "file"},
{name: "URL", value: "url"},
],
})
.then(({docType}) => {
if (docType === "file") {
Expand All @@ -373,7 +391,10 @@ export function decryptDocument(IronNode: SDK) {
name: "docType",
type: "list",
message: "What type of document is this?",
choices: [{name: "Direct Input", value: "direct"}, {name: "File", value: "file"}],
choices: [
{name: "Direct Input", value: "direct"},
{name: "File", value: "file"},
],
})
.then(({docType}) => {
if (docType === "direct") {
Expand Down Expand Up @@ -410,7 +431,10 @@ export function updateDocumentData(IronNode: SDK) {
name: "docType",
type: "list",
message: "What type of document is this?",
choices: [{name: "Direct Input", value: "direct"}, {name: "File", value: "file"}],
choices: [
{name: "Direct Input", value: "direct"},
{name: "File", value: "file"},
],
})
.then(({docType}) => {
if (docType === "direct") {
Expand Down
1 change: 1 addition & 0 deletions ironnode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface DocumentCreateOptions {
documentID?: string;
documentName?: string;
accessList?: DocumentAccessList;
grantToAuthor?: boolean;
}
export interface GroupCreateOptions {
groupID?: string;
Expand Down
22 changes: 10 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,19 @@
},
"devDependencies": {
"@types/inquirer": "^6.5.0",
"@types/jest": "^24.0.18",
"@types/jsonwebtoken": "^8.3.4",
"@types/node": "^12.7.5",
"@types/node-fetch": "^2.5.1",
"@types/request": "^2.48.3",
"inquirer": "^7.0.0",
"jest": "^24.9.0",
"jest-extended": "^0.11.2",
"@types/jest": "^25.1.2",
"@types/jsonwebtoken": "^8.3.7",
"@types/node": "^12.12.27",
"@types/node-fetch": "^2.5.4",
"inquirer": "^7.0.4",
"jest": "^25.1.0",
"jest-extended": "^0.11.5",
"jsonwebtoken": "^8.5.1",
"request": "^2.88.0",
"shelljs": "^0.8.3",
"ts-jest": "^24.1.0",
"ts-node": "^8.4.1",
"ts-jest": "^25.2.0",
"ts-node": "^8.6.2",
"tslint": "^5.20.0",
"typescript": "^3.6.3",
"typescript": "^3.7.5",
"typestrict": "^1.0.2"
},
"prettier": {
Expand Down
8 changes: 4 additions & 4 deletions src/api/DocumentApi.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {DocumentAssociation} from "../../ironnode";
import {Base64String, EncryptedAccessKey, MessageSignature, PublicKey, TransformedEncryptedMessage, UserOrGroup} from "../commonTypes";
import {ErrorCodes, UserAndGroupTypes} from "../Constants";
import ApiState from "../lib/ApiState";
import {Codec} from "../lib/Utils";
import * as ApiRequest from "./ApiRequest";
import ApiState from "../lib/ApiState";
import {DocumentAssociation} from "../../ironnode";
import {TransformedEncryptedMessage, Base64String, UserOrGroup, EncryptedAccessKey, MessageSignature, PublicKey} from "../commonTypes";

interface DocumentMetaApiResponse {
id: string;
name: string;
name: string | null;
association: {
type: DocumentAssociation;
};
Expand Down
10 changes: 5 additions & 5 deletions src/crypto/StreamingAES.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as crypto from "crypto";
import {Transform, TransformCallback} from "stream";
import {AES_ALGORITHM, AES_IV_LENGTH, AES_BLOCK_SIZE, AES_GCM_TAG_LENGTH, VERSION_HEADER_LENGTH} from "../Constants";
import {AES_ALGORITHM, AES_BLOCK_SIZE, AES_GCM_TAG_LENGTH, AES_IV_LENGTH, VERSION_HEADER_LENGTH} from "../Constants";

//tslint:disable:max-classes-per-file

Expand All @@ -24,7 +24,7 @@ export class StreamingEncryption {
getTransform() {
//tslint:disable-next-line:no-this-assignment
const streamClass = this;
return function transform(this: NodeJS.ReadStream, chunk: Buffer, _: string, callback: TransformCallback) {
return function transform(this: Transform, chunk: Buffer, _: string, callback: TransformCallback) {
//Check if this is our first transform operation. If so, we need to shove the IV at the front of the resulting
//buffer in unencrypted form so we can pull it out on decryption.
if (!streamClass.hasPushedOnIV) {
Expand All @@ -46,7 +46,7 @@ export class StreamingEncryption {
getFlush() {
//tslint:disable-next-line:no-this-assignment
const streamClass = this;
return function flush(this: NodeJS.ReadStream, callback: TransformCallback) {
return function flush(this: Transform, callback: TransformCallback) {
//This will only happen if the user is somehow streaming in an empty file. A pretty dumb use case I'll grant you, but it's easy enough to support
if (!streamClass.hasPushedOnIV) {
this.push(streamClass.documentHeader);
Expand Down Expand Up @@ -122,7 +122,7 @@ export class StreamingDecryption {
getTransform() {
//tslint:disable-next-line:no-this-assignment
const streamClass = this;
return function transform(this: NodeJS.ReadStream, chunk: Buffer, _: string, callback: TransformCallback) {
return function transform(this: Transform, chunk: Buffer, _: string, callback: TransformCallback) {
//Don't do anything if we don't get any data for some odd reason
if (!chunk.length) {
return callback();
Expand Down Expand Up @@ -162,7 +162,7 @@ export class StreamingDecryption {
getFlush() {
//tslint:disable-next-line:no-this-assignment
const streamClass = this;
return function flush(this: NodeJS.ReadStream, callback: TransformCallback) {
return function flush(this: Transform, callback: TransformCallback) {
//If we get a flush call before we got a transform call where we setup the decipher, that likely means the file was empty
if (!streamClass.decipher) {
return callback(new Error("Data could not be read from input stream."));
Expand Down
Loading

0 comments on commit 00fe73f

Please sign in to comment.