Browse Source

Added base for uploading content files

master
Teknikode 3 years ago
parent
commit
77e792292d

+ 0
- 20
content/background.html View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<textarea id="ta"></textarea>
<script src="../scripts/JQuery/jquery-3.1.1.min.js"></script>
<script src="../scripts/Crypto-js/aes.js"></script>
<script src="../scripts/Crypto-js/enc-base64.js"></script>
<script src="../scripts/Crypto-js/mode-ctr.js"></script>
<script src="../scripts/Crypto-js/lib-typedarrays.js"></script>
<script src="../scripts/Crypto-js/pad-nopadding.js"></script>
<script src="../scripts/common.js"></script>
<script src="../scripts/upload.js"></script>
<script src="../scripts/paste.js"></script>
<script src="../scripts/shorten.js"></script>
<script src="../scripts/background.js"></script>
</body>
</html>

settings/options.css → content/options.css View File


dialog/popup.css → content/popup.css View File

@@ -2,20 +2,13 @@ html, body {
width: 100px;
}

.button {
button {
margin: 3% auto;
padding: 4px;
text-align: center;
font-size: 1.5em;
cursor: pointer;
}

.option:hover {
background-color: #CFF2F2;
}

.option {
background-color: #E5F2F2;
width: 100%;
}

.clear {

+ 0
- 19
dialog/popup.html View File

@@ -1,19 +0,0 @@
<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="popup.css"/>
</head>

<body>
<div class="button option">Encrypt</div>
<div class="button option">Gen Del</div>
<div class="button option">Shorten</div>
<div class="button option">Paste</div>
<div class="button clear">Reset</div>

<script src="popup.js"></script>
</body>

</html>

+ 0
- 18
dialog/popup.js View File

@@ -1,18 +0,0 @@
/*
Listen for clicks in the popup.

If it's on a button which contains class "clear":
Reload the page.
Close the popup. This is needed, as the content script malfunctions after page reloads.
*/

document.addEventListener("click", (e) => {
if (e.target.classList.contains("option")) {
var chosenOption = e.target.textContent;
alert(chosenOption);
}
else if (e.target.classList.contains("clear")) {
browser.tabs.reload();
window.close();
}
});

+ 16
- 5
manifest.json View File

@@ -1,9 +1,9 @@
{
"manifest_version": 2,
"name": "Teknik Uploader",
"name": "Teknik Extender",
"version": "1.0",

"description": "Uploads files to Teknik and adds the link to your clipboard.",
"description": "Allows easy methods to utilize the Teknik Services.",
"applications": {
"gecko": {
@@ -26,7 +26,7 @@
"48": "images/favicon-48.png"
},
"default_title": "Teknik Upload",
"default_popup": "dialog/popup.html"
"default_popup": "views/popup.html"
},

"icons": {
@@ -35,10 +35,21 @@
},

"background": {
"page": "content/background.html"
"scripts": [
"scripts/JQuery/jquery-3.1.1.min.js",
"scripts/Crypto-js/crypto-js.min.js",
"scripts/secure-random/secure-random.js",
"scripts/Mozilla/browser-polyfill.js",
"scripts/common.js",
"scripts/upload.js",
"scripts/paste.js",
"scripts/shorten.js",
"scripts/background.js"
],
"persistent": false
},
"options_ui": {
"page": "settings/options.html"
"page": "views/options.html"
}
}

+ 1
- 0
scripts/Crypto-js/crypto-js.min.js
File diff suppressed because it is too large
View File


+ 115
- 0
scripts/EncryptionWorker.js View File

@@ -0,0 +1,115 @@
self.addEventListener('message', function (e) {
importScripts(e.data.script);
var bytes = new Uint8Array(e.data.file);

var startByte = 0;
var endByte = 0;
var prog;

var key = CryptoJS.enc.Utf8.parse(e.data.key);
var iv = CryptoJS.enc.Utf8.parse(e.data.iv);

// Create aes encryptor object
var aesCrypto;
switch (e.data.cmd) {
case 'encrypt':
aesCrypto = CryptoJS.algo.AES.createEncryptor(key, { iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
break;
case 'decrypt':
aesCrypto = CryptoJS.algo.AES.createDecryptor(key, { iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
break;
default:
break;
}

while (startByte <= (bytes.length - 1)) {
// Set the end byte
endByte = startByte + e.data.chunkSize;
if (endByte > bytes.length - 1) {
endByte = bytes.length;
}

// Grab current set of bytes
var curBytes = bytes.subarray(startByte, endByte);

//var b64encoded = btoa(String.fromCharCode.apply(null, curBytes));
var wordArray = CryptoJS.lib.WordArray.create(curBytes)

// encrypt the passed in file data
var enc = aesCrypto.process(wordArray);

// Convert and add to current array buffer
var encStr = enc.toString(CryptoJS.enc.Base64); // to string
if (prog == null) {
prog = _base64ToArray(encStr);
}
else {
prog = Uint8Concat(prog, _base64ToArray(encStr));
}

// Send an update on progress
var objData =
{
cmd: 'progress',
processed: endByte,
total: bytes.length - 1
};

self.postMessage(objData);

// Set the next start as the current end
startByte = endByte;
}

//then finalize
var encFinal = aesCrypto.finalize();
var finalStr = encFinal.toString(CryptoJS.enc.Base64); // to final string
prog = Uint8Concat(prog, _base64ToArray(finalStr));

var objData =
{
cmd: 'progress',
processed: bytes.length - 1,
total: bytes.length - 1
};

// Now package it into a mesage to send home
var objData =
{
cmd: 'finish',
buffer: prog.buffer
};

self.postMessage(objData, [objData.buffer]);
}, false);

function _arrayToArrayBuffer(array) {
var len = array.length;
var bytes = new Uint8Array(len);
bytes.set(array, 0);
return bytes.buffer;
}

function _base64ToArray(base64) {
var binary_string = atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
}

Array.prototype.pushArray = function (arr) {
this.push.apply(this, arr);
};

function Uint8Concat(first, second) {
var firstLength = first.length;
var result = new Uint8Array(firstLength + second.length);

result.set(first);
result.set(second, firstLength);

return result;
}

+ 851
- 0
scripts/Mozilla/browser-polyfill.js View File

@@ -0,0 +1,851 @@
/* webextension-polyfill - v0.1.0 - Mon Jan 23 2017 22:18:10 */
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

if (typeof browser === "undefined") {
// Wrapping the bulk of this polyfill in a one-time-use function is a minor
// optimization for Firefox. Since Spidermonkey does not fully parse the
// contents of a function until the first time it's called, and since it will
// never actually need to be called, this allows the polyfill to be included
// in Firefox nearly for free.
const wrapAPIs = () => {
const apiMetadata = {
"alarms": {
"clear": {
"minArgs": 0,
"maxArgs": 1
},
"clearAll": {
"minArgs": 0,
"maxArgs": 0
},
"get": {
"minArgs": 0,
"maxArgs": 1
},
"getAll": {
"minArgs": 0,
"maxArgs": 0
}
},
"bookmarks": {
"create": {
"minArgs": 1,
"maxArgs": 1
},
"export": {
"minArgs": 0,
"maxArgs": 0
},
"get": {
"minArgs": 1,
"maxArgs": 1
},
"getChildren": {
"minArgs": 1,
"maxArgs": 1
},
"getRecent": {
"minArgs": 1,
"maxArgs": 1
},
"getTree": {
"minArgs": 0,
"maxArgs": 0
},
"getSubTree": {
"minArgs": 1,
"maxArgs": 1
},
"import": {
"minArgs": 0,
"maxArgs": 0
},
"move": {
"minArgs": 2,
"maxArgs": 2
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"removeTree": {
"minArgs": 1,
"maxArgs": 1
},
"search": {
"minArgs": 1,
"maxArgs": 1
},
"update": {
"minArgs": 2,
"maxArgs": 2
}
},
"browserAction": {
"getBadgeBackgroundColor": {
"minArgs": 1,
"maxArgs": 1
},
"getBadgeText": {
"minArgs": 1,
"maxArgs": 1
},
"getPopup": {
"minArgs": 1,
"maxArgs": 1
},
"getTitle": {
"minArgs": 1,
"maxArgs": 1
},
"setIcon": {
"minArgs": 1,
"maxArgs": 1
}
},
"commands": {
"getAll": {
"minArgs": 0,
"maxArgs": 0
}
},
"contextMenus": {
"update": {
"minArgs": 2,
"maxArgs": 2
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"removeAll": {
"minArgs": 0,
"maxArgs": 0
}
},
"cookies": {
"get": {
"minArgs": 1,
"maxArgs": 1
},
"getAll": {
"minArgs": 1,
"maxArgs": 1
},
"getAllCookieStores": {
"minArgs": 0,
"maxArgs": 0
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"set": {
"minArgs": 1,
"maxArgs": 1
}
},
"downloads": {
"download": {
"minArgs": 1,
"maxArgs": 1
},
"cancel": {
"minArgs": 1,
"maxArgs": 1
},
"erase": {
"minArgs": 1,
"maxArgs": 1
},
"getFileIcon": {
"minArgs": 1,
"maxArgs": 2
},
"open": {
"minArgs": 1,
"maxArgs": 1
},
"pause": {
"minArgs": 1,
"maxArgs": 1
},
"removeFile": {
"minArgs": 1,
"maxArgs": 1
},
"resume": {
"minArgs": 1,
"maxArgs": 1
},
"search": {
"minArgs": 1,
"maxArgs": 1
},
"show": {
"minArgs": 1,
"maxArgs": 1
}
},
"extension": {
"isAllowedFileSchemeAccess": {
"minArgs": 0,
"maxArgs": 0
},
"isAllowedIncognitoAccess": {
"minArgs": 0,
"maxArgs": 0
}
},
"history": {
"addUrl": {
"minArgs": 1,
"maxArgs": 1
},
"getVisits": {
"minArgs": 1,
"maxArgs": 1
},
"deleteAll": {
"minArgs": 0,
"maxArgs": 0
},
"deleteRange": {
"minArgs": 1,
"maxArgs": 1
},
"deleteUrl": {
"minArgs": 1,
"maxArgs": 1
},
"search": {
"minArgs": 1,
"maxArgs": 1
}
},
"i18n": {
"detectLanguage": {
"minArgs": 1,
"maxArgs": 1
},
"getAcceptLanguages": {
"minArgs": 0,
"maxArgs": 0
}
},
"idle": {
"queryState": {
"minArgs": 1,
"maxArgs": 1
}
},
"management": {
"get": {
"minArgs": 1,
"maxArgs": 1
},
"getAll": {
"minArgs": 0,
"maxArgs": 0
},
"getSelf": {
"minArgs": 0,
"maxArgs": 0
},
"uninstallSelf": {
"minArgs": 0,
"maxArgs": 1
}
},
"notifications": {
"clear": {
"minArgs": 1,
"maxArgs": 1
},
"create": {
"minArgs": 1,
"maxArgs": 2
},
"getAll": {
"minArgs": 0,
"maxArgs": 0
},
"getPermissionLevel": {
"minArgs": 0,
"maxArgs": 0
},
"update": {
"minArgs": 2,
"maxArgs": 2
}
},
"pageAction": {
"getPopup": {
"minArgs": 1,
"maxArgs": 1
},
"getTitle": {
"minArgs": 1,
"maxArgs": 1
},
"hide": {
"minArgs": 0,
"maxArgs": 0
},
"setIcon": {
"minArgs": 1,
"maxArgs": 1
},
"show": {
"minArgs": 0,
"maxArgs": 0
}
},
"runtime": {
"getBackgroundPage": {
"minArgs": 0,
"maxArgs": 0
},
"getBrowserInfo": {
"minArgs": 0,
"maxArgs": 0
},
"getPlatformInfo": {
"minArgs": 0,
"maxArgs": 0
},
"openOptionsPage": {
"minArgs": 0,
"maxArgs": 0
},
"requestUpdateCheck": {
"minArgs": 0,
"maxArgs": 0
},
"sendMessage": {
"minArgs": 1,
"maxArgs": 3
},
"sendNativeMessage": {
"minArgs": 2,
"maxArgs": 2
},
"setUninstallURL": {
"minArgs": 1,
"maxArgs": 1
}
},
"storage": {
"local": {
"clear": {
"minArgs": 0,
"maxArgs": 0
},
"get": {
"minArgs": 0,
"maxArgs": 1
},
"getBytesInUse": {
"minArgs": 0,
"maxArgs": 1
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"set": {
"minArgs": 1,
"maxArgs": 1
}
},
"managed": {
"get": {
"minArgs": 0,
"maxArgs": 1
},
"getBytesInUse": {
"minArgs": 0,
"maxArgs": 1
}
},
"sync": {
"clear": {
"minArgs": 0,
"maxArgs": 0
},
"get": {
"minArgs": 0,
"maxArgs": 1
},
"getBytesInUse": {
"minArgs": 0,
"maxArgs": 1
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"set": {
"minArgs": 1,
"maxArgs": 1
}
}
},
"tabs": {
"create": {
"minArgs": 1,
"maxArgs": 1
},
"captureVisibleTab": {
"minArgs": 0,
"maxArgs": 2
},
"detectLanguage": {
"minArgs": 0,
"maxArgs": 1
},
"duplicate": {
"minArgs": 1,
"maxArgs": 1
},
"executeScript": {
"minArgs": 1,
"maxArgs": 2
},
"get": {
"minArgs": 1,
"maxArgs": 1
},
"getCurrent": {
"minArgs": 0,
"maxArgs": 0
},
"getZoom": {
"minArgs": 0,
"maxArgs": 1
},
"getZoomSettings": {
"minArgs": 0,
"maxArgs": 1
},
"highlight": {
"minArgs": 1,
"maxArgs": 1
},
"insertCSS": {
"minArgs": 1,
"maxArgs": 2
},
"move": {
"minArgs": 2,
"maxArgs": 2
},
"reload": {
"minArgs": 0,
"maxArgs": 2
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"query": {
"minArgs": 1,
"maxArgs": 1
},
"removeCSS": {
"minArgs": 1,
"maxArgs": 2
},
"sendMessage": {
"minArgs": 2,
"maxArgs": 3
},
"setZoom": {
"minArgs": 1,
"maxArgs": 2
},
"setZoomSettings": {
"minArgs": 1,
"maxArgs": 2
},
"update": {
"minArgs": 1,
"maxArgs": 2
}
},
"webNavigation": {
"getAllFrames": {
"minArgs": 1,
"maxArgs": 1
},
"getFrame": {
"minArgs": 1,
"maxArgs": 1
}
},
"webRequest": {
"handlerBehaviorChanged": {
"minArgs": 0,
"maxArgs": 0
}
},
"windows": {
"create": {
"minArgs": 0,
"maxArgs": 1
},
"get": {
"minArgs": 1,
"maxArgs": 2
},
"getAll": {
"minArgs": 0,
"maxArgs": 1
},
"getCurrent": {
"minArgs": 0,
"maxArgs": 1
},
"getLastFocused": {
"minArgs": 0,
"maxArgs": 1
},
"remove": {
"minArgs": 1,
"maxArgs": 1
},
"update": {
"minArgs": 2,
"maxArgs": 2
}
}
};

/**
* A WeakMap subclass which creates and stores a value for any key which does
* not exist when accessed, but behaves exactly as an ordinary WeakMap
* otherwise.
*
* @param {function} createItem
* A function which will be called in order to create the value for any
* key which does not exist, the first time it is accessed. The
* function receives, as its only argument, the key being created.
*/
class DefaultWeakMap extends WeakMap {
constructor(createItem, items = undefined) {
super(items);
this.createItem = createItem;
}

get(key) {
if (!this.has(key)) {
this.set(key, this.createItem(key));
}

return super.get(key);
}
}

/**
* Returns true if the given object is an object with a `then` method, and can
* therefore be assumed to behave as a Promise.
*
* @param {*} value The value to test.
* @returns {boolean} True if the value is thenable.
*/
const isThenable = value => {
return value && typeof value === "object" && typeof value.then === "function";
};

/**
* Creates and returns a function which, when called, will resolve or reject
* the given promise based on how it is called:
*
* - If, when called, `chrome.runtime.lastError` contains a non-null object,
* the promise is rejected with that value.
* - If the function is called with exactly one argument, the promise is
* resolved to that value.
* - Otherwise, the promise is resolved to an array containing all of the
* function's arguments.
*
* @param {object} promise
* An object containing the resolution and rejection functions of a
* promise.
* @param {function} promise.resolve
* The promise's resolution function.
* @param {function} promise.rejection
* The promise's rejection function.
*
* @returns {function}
* The generated callback function.
*/
const makeCallback = promise => {
return (...callbackArgs) => {
if (chrome.runtime.lastError) {
promise.reject(chrome.runtime.lastError);
} else if (callbackArgs.length === 1) {
promise.resolve(callbackArgs[0]);
} else {
promise.resolve(callbackArgs);
}
};
};

/**
* Creates a wrapper function for a method with the given name and metadata.
*
* @param {string} name
* The name of the method which is being wrapped.
* @param {object} metadata
* Metadata about the method being wrapped.
* @param {integer} metadata.minArgs
* The minimum number of arguments which must be passed to the
* function. If called with fewer than this number of arguments, the
* wrapper will raise an exception.
* @param {integer} metadata.maxArgs
* The maximum number of arguments which may be passed to the
* function. If called with more than this number of arguments, the
* wrapper will raise an exception.
*
* @returns {function(object, ...*)}
* The generated wrapper function.
*/
const wrapAsyncFunction = (name, metadata) => {
const pluralizeArguments = (numArgs) => numArgs == 1 ? "argument" : "arguments";

return function asyncFunctionWrapper(target, ...args) {
if (args.length < metadata.minArgs) {
throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);
}

if (args.length > metadata.maxArgs) {
throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);
}

return new Promise((resolve, reject) => {
target[name](...args, makeCallback({resolve, reject}));
});
};
};

/**
* Wraps an existing method of the target object, so that calls to it are
* intercepted by the given wrapper function. The wrapper function receives,
* as its first argument, the original `target` object, followed by each of
* the arguments passed to the orginal method.
*
* @param {object} target
* The original target object that the wrapped method belongs to.
* @param {function} method
* The method being wrapped. This is used as the target of the Proxy
* object which is created to wrap the method.
* @param {function} wrapper
* The wrapper function which is called in place of a direct invocation
* of the wrapped method.
*
* @returns {Proxy<function>}
* A Proxy object for the given method, which invokes the given wrapper
* method in its place.
*/
const wrapMethod = (target, method, wrapper) => {
return new Proxy(method, {
apply(targetMethod, thisObj, args) {
return wrapper.call(thisObj, target, ...args);
},
});
};

let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);

/**
* Wraps an object in a Proxy which intercepts and wraps certain methods
* based on the given `wrappers` and `metadata` objects.
*
* @param {object} target
* The target object to wrap.
*
* @param {object} [wrappers = {}]
* An object tree containing wrapper functions for special cases. Any
* function present in this object tree is called in place of the
* method in the same location in the `target` object tree. These
* wrapper methods are invoked as described in {@see wrapMethod}.
*
* @param {object} [metadata = {}]
* An object tree containing metadata used to automatically generate
* Promise-based wrapper functions for asynchronous. Any function in
* the `target` object tree which has a corresponding metadata object
* in the same location in the `metadata` tree is replaced with an
* automatically-generated wrapper function, as described in
* {@see wrapAsyncFunction}
*
* @returns {Proxy<object>}
*/
const wrapObject = (target, wrappers = {}, metadata = {}) => {
let cache = Object.create(null);

let handlers = {
has(target, prop) {
return prop in target || prop in cache;
},

get(target, prop, receiver) {
if (prop in cache) {
return cache[prop];
}

if (!(prop in target)) {
return undefined;
}

let value = target[prop];

if (typeof value === "function") {
// This is a method on the underlying object. Check if we need to do
// any wrapping.

if (typeof wrappers[prop] === "function") {
// We have a special-case wrapper for this method.
value = wrapMethod(target, target[prop], wrappers[prop]);
} else if (hasOwnProperty(metadata, prop)) {
// This is an async method that we have metadata for. Create a
// Promise wrapper for it.
let wrapper = wrapAsyncFunction(prop, metadata[prop]);
value = wrapMethod(target, target[prop], wrapper);
} else {
// This is a method that we don't know or care about. Return the
// original method, bound to the underlying object.
value = value.bind(target);
}
} else if (typeof value === "object" && value !== null &&
(hasOwnProperty(wrappers, prop) ||
hasOwnProperty(metadata, prop))) {
// This is an object that we need to do some wrapping for the children
// of. Create a sub-object wrapper for it with the appropriate child
// metadata.
value = wrapObject(value, wrappers[prop], metadata[prop]);
} else {
// We don't need to do any wrapping for this property,
// so just forward all access to the underlying object.
Object.defineProperty(cache, prop, {
configurable: true,
enumerable: true,
get() {
return target[prop];
},
set(value) {
target[prop] = value;
},
});

return value;
}

cache[prop] = value;
return value;
},

set(target, prop, value, receiver) {
if (prop in cache) {
cache[prop] = value;
} else {
target[prop] = value;
}
return true;
},

defineProperty(target, prop, desc) {
return Reflect.defineProperty(cache, prop, desc);
},

deleteProperty(target, prop) {
return Reflect.deleteProperty(cache, prop);
},
};

return new Proxy(target, handlers);
};

/**
* Creates a set of wrapper functions for an event object, which handles
* wrapping of listener functions that those messages are passed.
*
* A single wrapper is created for each listener function, and stored in a
* map. Subsequent calls to `addListener`, `hasListener`, or `removeListener`
* retrieve the original wrapper, so that attempts to remove a
* previously-added listener work as expected.
*
* @param {DefaultWeakMap<function, function>} wrapperMap
* A DefaultWeakMap object which will create the appropriate wrapper
* for a given listener function when one does not exist, and retrieve
* an existing one when it does.
*
* @returns {object}
*/
const wrapEvent = wrapperMap => ({
addListener(target, listener, ...args) {
target.addListener(wrapperMap.get(listener), ...args);
},

hasListener(target, listener) {
return target.hasListener(wrapperMap.get(listener));
},

removeListener(target, listener) {
target.removeListener(wrapperMap.get(listener));
},
});

const onMessageWrappers = new DefaultWeakMap(listener => {
if (typeof listener !== "function") {
return listener;
}

/**
* Wraps a message listener function so that it may send responses based on
* its return value, rather than by returning a sentinel value and calling a
* callback. If the listener function returns a Promise, the response is
* sent when the promise either resolves or rejects.
*
* @param {*} message
* The message sent by the other end of the channel.
* @param {object} sender
* Details about the sender of the message.
* @param {function(*)} sendResponse
* A callback which, when called with an arbitrary argument, sends
* that value as a response.
* @returns {boolean}
* True if the wrapped listener returned a Promise, which will later
* yield a response. False otherwise.
*/
return function onMessage(message, sender, sendResponse) {
let result = listener(message, sender);

if (isThenable(result)) {
result.then(sendResponse, error => {
console.error(error);
sendResponse(error);
});

return true;
} else if (result !== undefined) {
sendResponse(result);
}
};
});

const staticWrappers = {
runtime: {
onMessage: wrapEvent(onMessageWrappers),
},
};

return wrapObject(chrome, staticWrappers, apiMetadata);
};

this.browser = wrapAPIs();
}

+ 19
- 0
scripts/Mozilla/browser-polyfill.min.js View File

@@ -0,0 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
if(typeof browser==="undefined"){const wrapAPIs=()=>{const apiMetadata={"alarms":{"clear":{"minArgs":0,"maxArgs":1},"clearAll":{"minArgs":0,"maxArgs":0},"get":{"minArgs":0,"maxArgs":1},"getAll":{"minArgs":0,"maxArgs":0}},"bookmarks":{"create":{"minArgs":1,"maxArgs":1},"export":{"minArgs":0,"maxArgs":0},"get":{"minArgs":1,"maxArgs":1},"getChildren":{"minArgs":1,"maxArgs":1},"getRecent":{"minArgs":1,"maxArgs":1},"getTree":{"minArgs":0,"maxArgs":0},"getSubTree":{"minArgs":1,"maxArgs":1},"import":{"minArgs":0,
"maxArgs":0},"move":{"minArgs":2,"maxArgs":2},"remove":{"minArgs":1,"maxArgs":1},"removeTree":{"minArgs":1,"maxArgs":1},"search":{"minArgs":1,"maxArgs":1},"update":{"minArgs":2,"maxArgs":2}},"browserAction":{"getBadgeBackgroundColor":{"minArgs":1,"maxArgs":1},"getBadgeText":{"minArgs":1,"maxArgs":1},"getPopup":{"minArgs":1,"maxArgs":1},"getTitle":{"minArgs":1,"maxArgs":1},"setIcon":{"minArgs":1,"maxArgs":1}},"commands":{"getAll":{"minArgs":0,"maxArgs":0}},"contextMenus":{"update":{"minArgs":2,"maxArgs":2},
"remove":{"minArgs":1,"maxArgs":1},"removeAll":{"minArgs":0,"maxArgs":0}},"cookies":{"get":{"minArgs":1,"maxArgs":1},"getAll":{"minArgs":1,"maxArgs":1},"getAllCookieStores":{"minArgs":0,"maxArgs":0},"remove":{"minArgs":1,"maxArgs":1},"set":{"minArgs":1,"maxArgs":1}},"downloads":{"download":{"minArgs":1,"maxArgs":1},"cancel":{"minArgs":1,"maxArgs":1},"erase":{"minArgs":1,"maxArgs":1},"getFileIcon":{"minArgs":1,"maxArgs":2},"open":{"minArgs":1,"maxArgs":1},"pause":{"minArgs":1,"maxArgs":1},"removeFile":{"minArgs":1,
"maxArgs":1},"resume":{"minArgs":1,"maxArgs":1},"search":{"minArgs":1,"maxArgs":1},"show":{"minArgs":1,"maxArgs":1}},"extension":{"isAllowedFileSchemeAccess":{"minArgs":0,"maxArgs":0},"isAllowedIncognitoAccess":{"minArgs":0,"maxArgs":0}},"history":{"addUrl":{"minArgs":1,"maxArgs":1},"getVisits":{"minArgs":1,"maxArgs":1},"deleteAll":{"minArgs":0,"maxArgs":0},"deleteRange":{"minArgs":1,"maxArgs":1},"deleteUrl":{"minArgs":1,"maxArgs":1},"search":{"minArgs":1,"maxArgs":1}},"i18n":{"detectLanguage":{"minArgs":1,
"maxArgs":1},"getAcceptLanguages":{"minArgs":0,"maxArgs":0}},"idle":{"queryState":{"minArgs":1,"maxArgs":1}},"management":{"get":{"minArgs":1,"maxArgs":1},"getAll":{"minArgs":0,"maxArgs":0},"getSelf":{"minArgs":0,"maxArgs":0},"uninstallSelf":{"minArgs":0,"maxArgs":1}},"notifications":{"clear":{"minArgs":1,"maxArgs":1},"create":{"minArgs":1,"maxArgs":2},"getAll":{"minArgs":0,"maxArgs":0},"getPermissionLevel":{"minArgs":0,"maxArgs":0},"update":{"minArgs":2,"maxArgs":2}},"pageAction":{"getPopup":{"minArgs":1,
"maxArgs":1},"getTitle":{"minArgs":1,"maxArgs":1},"hide":{"minArgs":0,"maxArgs":0},"setIcon":{"minArgs":1,"maxArgs":1},"show":{"minArgs":0,"maxArgs":0}},"runtime":{"getBackgroundPage":{"minArgs":0,"maxArgs":0},"getBrowserInfo":{"minArgs":0,"maxArgs":0},"getPlatformInfo":{"minArgs":0,"maxArgs":0},"openOptionsPage":{"minArgs":0,"maxArgs":0},"requestUpdateCheck":{"minArgs":0,"maxArgs":0},"sendMessage":{"minArgs":1,"maxArgs":3},"sendNativeMessage":{"minArgs":2,"maxArgs":2},"setUninstallURL":{"minArgs":1,
"maxArgs":1}},"storage":{"local":{"clear":{"minArgs":0,"maxArgs":0},"get":{"minArgs":0,"maxArgs":1},"getBytesInUse":{"minArgs":0,"maxArgs":1},"remove":{"minArgs":1,"maxArgs":1},"set":{"minArgs":1,"maxArgs":1}},"managed":{"get":{"minArgs":0,"maxArgs":1},"getBytesInUse":{"minArgs":0,"maxArgs":1}},"sync":{"clear":{"minArgs":0,"maxArgs":0},"get":{"minArgs":0,"maxArgs":1},"getBytesInUse":{"minArgs":0,"maxArgs":1},"remove":{"minArgs":1,"maxArgs":1},"set":{"minArgs":1,"maxArgs":1}}},"tabs":{"create":{"minArgs":1,
"maxArgs":1},"captureVisibleTab":{"minArgs":0,"maxArgs":2},"detectLanguage":{"minArgs":0,"maxArgs":1},"duplicate":{"minArgs":1,"maxArgs":1},"executeScript":{"minArgs":1,"maxArgs":2},"get":{"minArgs":1,"maxArgs":1},"getCurrent":{"minArgs":0,"maxArgs":0},"getZoom":{"minArgs":0,"maxArgs":1},"getZoomSettings":{"minArgs":0,"maxArgs":1},"highlight":{"minArgs":1,"maxArgs":1},"insertCSS":{"minArgs":1,"maxArgs":2},"move":{"minArgs":2,"maxArgs":2},"reload":{"minArgs":0,"maxArgs":2},"remove":{"minArgs":1,"maxArgs":1},
"query":{"minArgs":1,"maxArgs":1},"removeCSS":{"minArgs":1,"maxArgs":2},"sendMessage":{"minArgs":2,"maxArgs":3},"setZoom":{"minArgs":1,"maxArgs":2},"setZoomSettings":{"minArgs":1,"maxArgs":2},"update":{"minArgs":1,"maxArgs":2}},"webNavigation":{"getAllFrames":{"minArgs":1,"maxArgs":1},"getFrame":{"minArgs":1,"maxArgs":1}},"webRequest":{"handlerBehaviorChanged":{"minArgs":0,"maxArgs":0}},"windows":{"create":{"minArgs":0,"maxArgs":1},"get":{"minArgs":1,"maxArgs":2},"getAll":{"minArgs":0,"maxArgs":1},
"getCurrent":{"minArgs":0,"maxArgs":1},"getLastFocused":{"minArgs":0,"maxArgs":1},"remove":{"minArgs":1,"maxArgs":1},"update":{"minArgs":2,"maxArgs":2}}};class DefaultWeakMap extends WeakMap{constructor(createItem,items=undefined){super(items);this.createItem=createItem}get(key){if(!this.has(key))this.set(key,this.createItem(key));return super.get(key)}}const isThenable=(value)=>{return value&&typeof value==="object"&&typeof value.then==="function"};const makeCallback=(promise)=>{return(...callbackArgs)=>
{if(chrome.runtime.lastError)promise.reject(chrome.runtime.lastError);else if(callbackArgs.length===1)promise.resolve(callbackArgs[0]);else promise.resolve(callbackArgs)}};const wrapAsyncFunction=(name,metadata)=>{const pluralizeArguments=(numArgs)=>numArgs==1?"argument":"arguments";return function asyncFunctionWrapper(target,...args){if(args.length<metadata.minArgs)throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);if(args.length>
metadata.maxArgs)throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);return new Promise((resolve,reject)=>{target[name](...args,makeCallback({resolve,reject}))})}};const wrapMethod=(target,method,wrapper)=>{return new Proxy(method,{apply(targetMethod,thisObj,args){return wrapper.call(thisObj,target,...args)}})};let hasOwnProperty=Function.call.bind(Object.prototype.hasOwnProperty);const wrapObject=(target,wrappers={},metadata=
{})=>{let cache=Object.create(null);let handlers={has(target,prop){return prop in target||prop in cache},get(target,prop,receiver){if(prop in cache)return cache[prop];if(!(prop in target))return undefined;let value=target[prop];if(typeof value==="function")if(typeof wrappers[prop]==="function")value=wrapMethod(target,target[prop],wrappers[prop]);else if(hasOwnProperty(metadata,prop)){let wrapper=wrapAsyncFunction(prop,metadata[prop]);value=wrapMethod(target,target[prop],wrapper)}else value=value.bind(target);
else if(typeof value==="object"&&value!==null&&(hasOwnProperty(wrappers,prop)||hasOwnProperty(metadata,prop)))value=wrapObject(value,wrappers[prop],metadata[prop]);else{Object.defineProperty(cache,prop,{configurable:true,enumerable:true,get(){return target[prop]},set(value){target[prop]=value}});return value}cache[prop]=value;return value},set(target,prop,value,receiver){if(prop in cache)cache[prop]=value;else target[prop]=value;return true},defineProperty(target,prop,desc){return Reflect.defineProperty(cache,
prop,desc)},deleteProperty(target,prop){return Reflect.deleteProperty(cache,prop)}};return new Proxy(target,handlers)};const wrapEvent=(wrapperMap)=>{addListener(target,listener,...args){target.addListener(wrapperMap.get(listener),...args)},hasListener(target,listener){return target.hasListener(wrapperMap.get(listener))},removeListener(target,listener){target.removeListener(wrapperMap.get(listener))}};const onMessageWrappers=new DefaultWeakMap((listener)=>{if(typeof listener!=="function")return listener;
return function onMessage(message,sender,sendResponse){let result=listener(message,sender);if(isThenable(result)){result.then(sendResponse,(error)=>{console.error(error);sendResponse(error)});return true}else if(result!==undefined)sendResponse(result)}});const staticWrappers={runtime:{onMessage:wrapEvent(onMessageWrappers)}};return wrapObject(chrome,staticWrappers,apiMetadata)};this.browser=wrapAPIs()};

+ 3
- 63
scripts/background.js View File

@@ -1,31 +1,3 @@
/*
Called when the item has been created, or when creation failed due to an error.
We'll just log success/failure here.
*/
function onCreated(n) {
if (browser.runtime.lastError) {
console.log('Error: ${browser.runtime.lastError}');
} else {
console.log("Item created successfully");
}
}

/*
Called when the item has been removed.
We'll just log success here.
*/
function onRemoved() {
console.log("Item removed successfully");
}

/*
Called when there was an error.
We'll just log the error here.
*/
function onError(error) {
console.log('Error: ${error}');
}

/*
Create all the context menu items.
*/
@@ -52,10 +24,6 @@ The click event listener, where we perform the appropriate action given the
ID of the menu item that was clicked.
*/
browser.contextMenus.onClicked.addListener(function(info, tab) {
var uploadUrl = 'https://api.teknik.io/v1/Upload';
var pasteUrl = 'https://api.teknik.io/v1/Paste';
var shortenUrl = 'https://api.teknik.io/v1/Shorten';

switch (info.menuItemId) {
case "upload-content":
// Get the media type
@@ -63,47 +31,19 @@ browser.contextMenus.onClicked.addListener(function(info, tab) {
// Get the url for the source
var srcUrl = info.srcUrl;
// Upload the content
console.log("Media: " + mediaType + " | Source: " + srcUrl);
uploadFromUrl(srcUrl);
break;
case "paste-selection":
// Get the selected text
var selectedText = info.selectionText;
// Paste the current selection
$.ajax({
type: "POST",
url: pasteUrl,
data: { code: selectedText },
success: function (response) {
if (response.result) {
var finalUrl = response.result.url;
copyTextToClipboard(finalUrl);
notify("Paste Created", "Paste has been created and saved to your clipboard.");
}
else {
notify("Paste Error", response.error.message);
}
}
});
createPaste(selectedText);
break;
case "shorten-url":
// Get the url
var fullUrl = info.linkUrl;
// Shorten the url
$.ajax({
type: "POST",
url: shortenUrl,
data: { url: fullUrl },
success: function (response) {
if (response.result) {
var finalUrl = response.result.shortUrl;
copyTextToClipboard(finalUrl);
notify("Url Shortened", "The Url has been shortened and saved to your clipboard.");
}
else {
notify("Shorten Error", response.error.message);
}
}
});
shortenUrl(fullUrl);
break;
}
});

+ 50
- 13
scripts/common.js View File

@@ -1,3 +1,36 @@
/*
Called when the item has been created, or when creation failed due to an error.
We'll just log success/failure here.
*/
function onCreated(n) {
if (browser.runtime.lastError) {
console.log('Error: ${browser.runtime.lastError}');
} else {
console.log("Item created successfully");
}
}

/*
Called when the item has been removed.
We'll just log success here.
*/
function onRemoved() {
console.log("Item removed successfully");
}

function onOpened() {
console.log('Options page opened');
}

/*
Called when there was an error.
We'll just log the error here.
*/
function onError(error) {
console.log('Error: ${error}');
}


function notify(title, message) {
browser.notifications.create({
"type": "basic",
@@ -7,18 +40,22 @@ function notify(title, message) {
});
}

function copyTextToClipboard(text) {
var result = false;
var textarea = document.getElementById('ta');
textarea.value = text;
textarea.select();

if (document.execCommand('copy')) {
result = true;
} else {
console.error('failed to get clipboard content');
}
function getFileExtension(fileName) {
var index = fileName.lastIndexOf('.');
return '.' + fileName.substr(index + 1);
}

textarea.value = '';
return result;
function GenerateBlobURL(url) {
var cachedBlob = null;
jQuery.ajax({
url: url,
success: function (result) {
var workerJSBlob = new Blob([result], {
type: "text/javascript"
});
cachedBlob = window.URL.createObjectURL(workerJSBlob);
},
async: false
});
return cachedBlob;
}

+ 17
- 0
scripts/content.js View File

@@ -0,0 +1,17 @@
browser.runtime.onMessage.addListener(copyTextToClipboard);

function copyTextToClipboard(text) {
var result = false;
var textarea = document.getElementById('ta');
textarea.value = text;
textarea.select();

if (document.execCommand('copy')) {
result = true;
} else {
console.error('failed to get clipboard content');
}

textarea.value = '';
return result;
}

settings/options.js → scripts/options.js View File


+ 1
- 2
scripts/paste.js View File

@@ -9,8 +9,7 @@ function createPaste(text) {
success: function (response) {
if (response.result) {
var pasteUrl = response.result.url;
copyTextToClipboard(pasteUrl);
notify("Paste Created", "Paste has been created and saved to your clipboard.");
browser.tabs.create({ url: pasteUrl });
}
else {
notify("Paste Error", response.error.message);

+ 10
- 0
scripts/popup.js View File

@@ -0,0 +1,10 @@
$(document).ready(function () {
$('#clearList').click(function () {
$('#itemList').html('<li>No Items</li>');
});
$('#settings').click(function () {
var opening = browser.runtime.openOptionsPage();
opening.then(onOpened, onError);
});
});

+ 78
- 0
scripts/secure-random/secure-random.js View File

@@ -0,0 +1,78 @@
!function(globals){
'use strict'

//*** UMD BEGIN
if (typeof define !== 'undefined' && define.amd) { //require.js / AMD
define([], function() {
return secureRandom
})
} else if (typeof module !== 'undefined' && module.exports) { //CommonJS
module.exports = secureRandom
} else { //script / browser
globals.secureRandom = secureRandom
}
//*** UMD END

//options.type is the only valid option
function secureRandom(count, options) {
options = options || {type: 'Array'}
//we check for process.pid to prevent browserify from tricking us
if (typeof process != 'undefined' && typeof process.pid == 'number') {
return nodeRandom(count, options)
} else {
var crypto = window.crypto || window.msCrypto
if (!crypto) throw new Error("Your browser does not support window.crypto.")
return browserRandom(count, options)
}
}

function nodeRandom(count, options) {
var crypto = require('crypto')
var buf = crypto.randomBytes(count)

switch (options.type) {
case 'Array':
return [].slice.call(buf)
case 'Buffer':
return buf
case 'Uint8Array':
var arr = new Uint8Array(count)
for (var i = 0; i < count; ++i) { arr[i] = buf.readUInt8(i) }
return arr
default:
throw new Error(options.type + " is unsupported.")
}
}

function browserRandom(count, options) {
var nativeArr = new Uint8Array(count)
var crypto = window.crypto || window.msCrypto
crypto.getRandomValues(nativeArr)

switch (options.type) {
case 'Array':
return [].slice.call(nativeArr)
case 'Buffer':
try { var b = new Buffer(1) } catch(e) { throw new Error('Buffer not supported in this environment. Use Node.js or Browserify for browser support.')}
return new Buffer(nativeArr)
case 'Uint8Array':
return nativeArr
default:
throw new Error(options.type + " is unsupported.")
}
}

secureRandom.randomArray = function(byteCount) {
return secureRandom(byteCount, {type: 'Array'})
}

secureRandom.randomUint8Array = function(byteCount) {
return secureRandom(byteCount, {type: 'Uint8Array'})
}

secureRandom.randomBuffer = function(byteCount) {
return secureRandom(byteCount, {type: 'Buffer'})
}


}(this);

+ 1
- 2
scripts/shorten.js View File

@@ -9,8 +9,7 @@ function shortenUrl(url) {
success: function (response) {
if (response.result) {
var shortUrl = response.result.shortUrl;
copyTextToClipboard(shortUrl);
notify("Url Shortened", "The Url has been shortened and saved to your clipboard.");
notify("Url Shortened", "The Url has been shortened to: " + shortUrl);
}
else {
notify("Shorten Error", response.error.message);

+ 161
- 0
scripts/upload.js View File

@@ -0,0 +1,161 @@
var encScriptSrc = 'EncryptionWorker.js';
var aesScriptSrc = 'Crypto-js/crypto-js.min.js';

function uploadFromUrl(contentUrl) {
// Download the file
var xhr = new XMLHttpRequest();
xhr.open('GET', contentUrl);
xhr.responseType = 'blob';
xhr.onload = function() {
// Encrypt the downloaded file
//encryptFile(xhr.response, 'application/octet-stream', false, false, false, 256, 128, uploadFile);
};
xhr.send();
}

// Function to encrypt a file, overide the file's data attribute with the encrypted value, and then call a callback function if supplied
function encryptFile(fileBlob, contentType, saveKey, serverSideEncrypt, genDelKey, keySize, blockSize, callback) {
// Start the file reader
var reader = new FileReader();

// When the file has been loaded, encrypt it
reader.onload = (function (callback) {
return function (e) {
// Create random key and iv (divide size by 8 for character length)
var keyBytes = secureRandom(keySize / 8);
var keyWords = CryptoJS.lib.WordArray.create(keyBytes);
var keyStr = keyWords.toString(CryptoJS.enc.Base64);
var ivBytes = secureRandom(blockSize / 8);
var ivWords = CryptoJS.lib.WordArray.create(ivBytes);
var ivStr = ivWords.toString(CryptoJS.enc.Base64);

// Encrypt on the server side if they ask for it
if (serverSideEncrypt) {
callback(e.target.result, keyStr, ivStr, contentType, saveKey, serverSideEncrypt, genDelKey);
}
else {
var worker = new Worker(GenerateBlobURL(encScriptSrc));

worker.addEventListener('message', function (e) {
switch (e.data.cmd) {
case 'progress':
var percentComplete = Math.round(e.data.processed * 100 / e.data.total);
// Display encryption progress
notify("Upload Progress", percentComplete + '% Encrypted');
break;
case 'finish':
if (callback != null) {
// Finish
callback(e.data.buffer, keyStr, ivStr, contentType, saveKey, serverSideEncrypt, genDelKey);
}
break;
}
});

worker.onerror = function (err) {
// An error occured
/* NOTIFY SOMEONE */
notify("Upload Error", err);
}

// Generate the script to include as a blob
var scriptBlob = GenerateBlobURL(aesScriptSrc);

// Execute worker with data
var objData =
{
cmd: 'encrypt',
script: scriptBlob,
key: keyStr,
iv: ivStr,
chunkSize: chunkSize,
file: e.target.result
};
worker.postMessage(objData, [objData.file]);
}
};
})(callback);

reader.onprogress = function (data) {
if (data.lengthComputable) {
var progress = parseInt(((data.loaded / data.total) * 100), 10);
// display loaded progress
notify("Upload Progress", percentComplete + '% Loaded');
}
}

// Start async read
reader.readAsArrayBuffer(fileBlob);
}

function uploadFile(data, key, iv, contentType, saveKey, serverSideEncrypt, genDelKey)
{
// Get the upload url
var uploadAPI = "https://api.teknik.io/v1/Upload";
// Create a blog from the data
var blob = new Blob([data]);
// Create the form data to send
var fd = new FormData();
fd.append('file', blob);
fd.append('contentType', filetype);
fd.append('saveKey', saveKey);
if (saveKey)
{
fd.append('key', key);
}
fd.append('keySize', keySize);
fd.append('iv', iv);
fd.append('blockSize', blockSize);
fd.append('encrypt', serverSideEncrypt);
fd.append('genDeletionKey', genDelKey);

// Send the form data and report the results
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress.bind(null), false);
xhr.addEventListener("load", uploadComplete.bind(null, key, saveKey), false);
xhr.addEventListener("error", uploadFailed.bind(null), false);
xhr.addEventListener("abort", uploadCanceled.bind(null), false);
xhr.open("POST", uploadAPI);
xhr.send(fd);
}

function uploadProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
notify("Upload Progress", percentComplete + '% Uploaded');
}
}

function uploadComplete(key, saveKey, evt) {
obj = JSON.parse(evt.target.responseText);
if (obj.result != null) {
var fullUrl = obj.result.url;
if (obj.result.key != null)
key = obj.result.key;
if (!saveKey) {
fullUrl = fullUrl + '#' + key;
}
// Open a new tab to the upload
browser.tabs.create({ url: fullUrl });
}
else
{
if (obj.error != null) {
notify("Upload Error", obj.error.message);
}
else {
notify("Upload Error", 'Unable to Upload File');
}
}
}

function uploadFailed(evt) {
notify("Upload Error", 'Upload Failed');
}

function uploadCanceled(evt) {
notify("Upload Error", 'Upload Canceled');
}

settings/options.html → views/options.html View File

@@ -9,14 +9,22 @@

<form>
<label for="username">Username</label>
<br />
<input type="text" id="username" />
<br />
<br />
<label for="authToken">Authentication Token</label>
<br />
<input type="text" id="authToken" />
<br />
<br />
<button type="submit">Save</button>
</form>

<script src="options.js"></script>
<script type="application/javascript" src="../scripts/Mozilla/browser-polyfill.js"></script>
<script type="application/javascript" src="../scripts/options.js"></script>

</body>


+ 21
- 0
views/popup.html View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../content/popup.css"/>
</head>

<body>
<ul id="itemList">
<li>No Items</li>
</ul>
<button class="button clear" id="clearList">Clear</button>
<hr>
<button class="button settings" id="settings">Settings</button>
<script type="application/javascript" src="../scripts/Mozilla/browser-polyfill.js"></script>
<script type="application/javascript" src="../scripts/popup.js"></script>
</body>

</html>

Loading…
Cancel
Save