Import core modules directly rather than compiling them under a namespace

This commit is contained in:
Martin Kleinschrodt 2018-05-30 16:29:04 +02:00
parent ce10f86145
commit d1f276f46d
17 changed files with 2678 additions and 256 deletions

View File

@ -1,6 +1,7 @@
{
"parserOptions": {
"ecmaVersion": "2015"
"ecmaVersion": "2017",
"sourceType": "module"
},
"env": {
"node": true,
@ -8,9 +9,7 @@
"browser": true
},
"extends": "eslint:recommended",
"plugins": [
"html"
],
"plugins": ["html"],
"globals": {
"Polymer": true,
"padlock": true,
@ -23,7 +22,7 @@
"comma-style": "error",
"curly": "error",
"eol-last": "warn",
"indent": ["error", 4, {"SwitchCase": 1, "outerIIFEBody": 0}],
"indent": ["error", 4, { "SwitchCase": 1, "outerIIFEBody": 0 }],
"key-spacing": "warn",
"keyword-spacing": "warn",
"linebreak-style": "error",
@ -31,7 +30,7 @@
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-loop-func": "error",
"no-multi-spaces": "error",
"no-multiple-empty-lines": ["error", {"max": 1, "maxBOF": 1, "maxEOF": 0}],
"no-multiple-empty-lines": ["error", { "max": 1, "maxBOF": 1, "maxEOF": 0 }],
"no-spaced-func": "error",
"no-trailing-spaces": "error",
"no-undef": "error",
@ -40,7 +39,7 @@
"no-use-before-define": "warn",
"no-whitespace-before-property": "error",
"operator-linebreak": ["error", "after"],
"quotes": ["error", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
"quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": true }],
"semi": "error",
"semi-spacing": "error",
"space-before-blocks": "error",

5
.gitignore vendored
View File

@ -8,5 +8,8 @@ cordova/platforms
cordova/plugins
cordova/www
app/lib
// Core files compiled from typescript
app/src/core/*.js
app/src/core/*.js.map
tests.js

7
.prettierrc.json Normal file
View File

@ -0,0 +1,7 @@
{
"printWidth": 120,
"tabWidth": 4,
"semi": true,
"singleQuote": false,
"bracketSpacing": true
}

View File

@ -1,11 +0,0 @@
import './src/ui/app/app.js';
import '../@webcomponents/webcomponentsjs/webcomponents-bundle.js';
const $_documentContainer = document.createElement('template');
$_documentContainer.setAttribute('style', 'display: none;');
$_documentContainer.innerHTML = `<title>Padlock</title><style> html, body {
background: #59c6ff;
margin: 0;
} </style><pl-app></pl-app>`;
document.head.appendChild($_documentContainer.content);

View File

@ -1,4 +1,4 @@
import * as sjcl from "sjcl";
import { sjcl } from "../vendor/sjcl";
import { isCordova, hasNode } from "./platform";
declare var pbkdf2: undefined |
@ -244,7 +244,7 @@ export class Container implements KeyParams, CipherParams {
// quietly accepted the string and simply treated it as an array.
// So in order to successfully decrypt legacy containers we have to
// perfom this conversion first.
raw.adata = bitsToBase64(raw.adata as any as sjcl.BitArray);
raw.adata = bitsToBase64(raw.adata);
break;
case 1:
break;

View File

@ -1,5 +1,5 @@
const moment = require("moment");
require("moment-duration-format");
import * as moment from "moment";
import "moment-duration-format";
// RFC4122-compliant uuid generator
export function uuid(): string {

View File

@ -19,13 +19,13 @@ import './auto-lock.js';
import './auto-sync.js';
import './hints.js';
import './messages.js';
import { getPlatformName, getDeviceInfo, isTouch } from "../../core/platform.js"
/* global cordova, StatusBar */
const { NotificationMixin, DialogMixin, MessagesMixin, DataMixin, AnimationMixin, ClipboardMixin,
SyncMixin, AutoSyncMixin, AutoLockMixin, HintsMixin, AnalyticsMixin, LocaleMixin, BaseElement } = padlock;
const { applyMixins } = padlock.util;
const { getPlatformName, getDeviceInfo, isTouch } = padlock.platform;
const cordovaReady = new Promise((resolve) => {
document.addEventListener("deviceready", resolve);

View File

@ -1,22 +1,23 @@
import '../../../../../node_modules/@polymer/polymer/polymer-legacy.js';
import { PolymerElement, html } from '../../../../../node_modules/@polymer/polymer/polymer-element.js';
import "@polymer/polymer/polymer-legacy";
import { PolymerElement, html } from "@polymer/polymer/polymer-element";
import "../../padlock.js";
window.Polymer = { html };
window.padlock = window.padlock || {};
padlock.BaseElement = class Base extends PolymerElement {
export class BaseElement extends PolymerElement {
truthy(val) {
return !!val;
}
equals(val, ...vals) {
return vals.some((v) => v === val);
return vals.some(v => v === val);
}
identity(val) {
return val;
}
};
}
padlock.BaseElement = BaseElement;

View File

@ -1,49 +1,43 @@
import { MutableData } from '../../../../../node_modules/@polymer/polymer/lib/mixins/mutable-data.js';
import '../base/base.js';
import '../locale/locale.js';
import { Polymer } from '../../../../../node_modules/@polymer/polymer/lib/legacy/polymer-fn.js';
const { Collection, Record, Settings } = padlock.data;
const { FileSource, EncryptedSource } = padlock.source;
const { getDesktopSettings } = padlock.platform;
import "../base/base";
import { MutableData } from "@polymer/polymer/lib/mixins/mutable-data";
import { localize as $l } from "../locale/locale";
import { Collection, Record, Settings } from "../../core/data";
import { FileSource, EncryptedSource, LocalStorageSource } from "../../core/source";
import { getDesktopSettings } from "../../core/platform";
import { debounce } from "../../core/util";
const desktopSettings = getDesktopSettings();
const dbPath = desktopSettings ? desktopSettings.get("dbPath") : "data.pls";
const collection = new Collection();
const localSource = new EncryptedSource(new FileSource(dbPath));
const settings = new Settings();
const settingsSource = new EncryptedSource(new FileSource("settings.pls"));
const dispatcher = document.createElement("div");
// transfer legacy data from LocalStorageSource to FileSource
function transferData(lsName, fileName) {
const lsSource = new padlock.source.LocalStorageSource(lsName);
const fileSource = new padlock.source.FileSource(fileName);
return Promise.all([lsSource.get(), fileSource.get()])
.then((data) => {
// Only transfer if there is existing localstorage data but no
// existing data in file storage
if (data[0] && !data[1]) {
return Promise.all([
fileSource.set(data[0]),
lsSource.clear()
]);
}
});
async function transferData(lsName, fileName) {
const lsSource = new LocalStorageSource(lsName);
const fileSource = new FileSource(fileName);
const data = await Promise.all([lsSource.get(), fileSource.get()]);
// Only transfer if there is existing localstorage data but no
// existing data in file storage
if (data[0] && !data[1]) {
await Promise.all([fileSource.set(data[0]), lsSource.clear()]);
return true;
} else {
return false;
}
}
const legacyDataTransfered = Promise.all([
transferData("coll_default", dbPath),
transferData("settings_encrypted", "settings.pls")
]);
const debouncedSaveSettings = debounce(() => settings.save(settingsSource), 500);
const debouncedSaveCollection = debounce(() => collection.save(localSource), 500);
const debouncedSaveSettings = padlock.util.debounce(() => settings.save(settingsSource), 500);
const debouncedSaveCollection = padlock.util.debounce(() => collection.save(localSource), 500);
dispatcher.addEventListener("record-changed", (e) => {
const record = e.detail;
dispatcher.addEventListener("record-changed", ({ detail }) => {
const record = detail;
record.updated = new Date();
debouncedSaveCollection();
});
@ -59,47 +53,50 @@ function filterByString(fs, rec) {
return true;
}
const words = fs.toLowerCase().split(" ");
const content = rec.tags.concat([rec.name]).join(" ").toLowerCase();
return words.some((word) => content.search(word) !== -1);
const content = rec.tags
.concat([rec.name])
.join(" ")
.toLowerCase();
return words.some(word => content.search(word) !== -1);
}
padlock.DataMixin = (superClass) => {
export function DataMixin(superClass) {
return class DataMixin extends MutableData(superClass) {
static get properties() { return {
collection: {
type: Object,
value: collection,
notify: true
},
filterString: {
type: String,
value: ""
},
records: {
type: Array,
notify: true,
computed: " _filterAndSort(collection.records, filterString)"
},
settings: {
type: Object,
value: settings,
notify: true
}
}; }
static get properties() {
return {
collection: {
type: Object,
value: collection,
notify: true
},
filterString: {
type: String,
value: ""
},
records: {
type: Array,
notify: true,
computed: "_filterAndSort(collection.records, filterString)"
},
settings: {
type: Object,
value: settings,
notify: true
}
};
}
constructor() {
super();
this.listen("record-created", (e) => this._recordCreated(e));
this.listen("record-deleted", (e) => this._recordDeleted(e));
this.listen("record-changed", (e) => this._recordChanged(e));
this.listen("records-changed", (e) => this._recordsChanged(e));
this.listen("data-initialized", (e) => this._dataInitialized(e));
this.listen("data-loaded", (e) => this._dataLoaded(e));
this.listen("data-unloaded", (e) => this._dataUnloaded(e));
this.listen("data-reset", (e) => this._dataReset(e));
this.listen("settings-changed", (e) => this._settingsChanged(e));
this.listen("record-created", e => this._recordCreated(e));
this.listen("record-deleted", e => this._recordDeleted(e));
this.listen("record-changed", e => this._recordChanged(e));
this.listen("records-changed", e => this._recordsChanged(e));
this.listen("data-initialized", () => this._dataInitialized());
this.listen("data-loaded", () => this._dataLoaded());
this.listen("data-unloaded", () => this._dataUnloaded());
this.listen("data-reset", () => this._dataReset());
this.listen("settings-changed", () => this._settingsChanged());
}
get password() {
@ -143,7 +140,7 @@ padlock.DataMixin = (superClass) => {
createRecord(name) {
const fields = [
{ name: $l("Username"), value: "", masked: false },
{ name: $l("Password"), value: "", masked: true },
{ name: $l("Password"), value: "", masked: true }
];
const record = new Record(name || "", fields);
this.addRecords([record]);
@ -158,7 +155,7 @@ padlock.DataMixin = (superClass) => {
}
deleteRecords(records) {
records.forEach((r) => r.remove());
records.forEach(r => r.remove());
this.saveCollection();
this.dispatch("records-changed");
}
@ -194,10 +191,7 @@ padlock.DataMixin = (superClass) => {
setPassword(password) {
localSource.password = settingsSource.password = password;
return Promise.all([
collection.save(localSource),
settings.save(settingsSource)
]);
return Promise.all([collection.save(localSource), settings.save(settingsSource)]);
}
unloadData() {
@ -269,24 +263,22 @@ padlock.DataMixin = (superClass) => {
}
_filterAndSort() {
let records = this.collection.records
.filter((r) => !r.removed && filterByString(this.filterString, r));
let records = this.collection.records.filter(r => !r.removed && filterByString(this.filterString, r));
this._recentCount = records.length > 10 ? 3 : 0;
const recent = records.sort((a, b) => {
return (b.lastUsed || b.updated).getTime() - (a.lastUsed || a.updated).getTime();
}).slice(0, this._recentCount);
const recent = records
.sort((a, b) => {
return (b.lastUsed || b.updated).getTime() - (a.lastUsed || a.updated).getTime();
})
.slice(0, this._recentCount);
records = records.slice(this._recentCount);
return recent.concat(records.sort((a, b) => Record.compare(a, b)));
}
};
}
};
Object.assign(padlock.DataMixin, {
Object.assign(DataMixin, {
collection,
settings
});
padlock.DataMixin = DataMixin;

View File

@ -1,9 +1,10 @@
import '../../styles/shared.js';
import '../base/base.js';
import "../../styles/shared";
import { BaseElement } from "../base/base";
import { html } from "@polymer/polymer/polymer-element";
class PlIcon extends padlock.BaseElement {
static get template() {
return Polymer.html`
export class PlIcon extends BaseElement {
static get template() {
return html `
<style include="shared">
:host {
display: inline-block;
@ -215,16 +216,17 @@ class PlIcon extends padlock.BaseElement {
<div></div>
`;
}
}
static get is() { return "pl-icon"; }
static get is() { return "pl-icon"; }
static get properties() { return {
icon: {
type: String,
reflectToAttribute: true
}
}; }
static get properties() {
return {
icon: {
type: String,
reflectToAttribute: true
}
};
}
}
window.customElements.define(PlIcon.is, PlIcon);

File diff suppressed because one or more lines are too long

2
app/src/vendor/sjcl.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
export var sjcl: any

2528
app/src/vendor/sjcl.js vendored Normal file

File diff suppressed because it is too large Load Diff

33
package-lock.json generated
View File

@ -174,6 +174,15 @@
"integrity": "sha512-b6gVDoxEbAQGwbV7gSzeFw/hy3/eEAokztktdzl4bHvGgb9K5zW4mVQDlVYch2w31m8t/J7L2iqhQvz3r5edCQ==",
"dev": true
},
"@types/moment-duration-format": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@types/moment-duration-format/-/moment-duration-format-2.2.0.tgz",
"integrity": "sha512-TpyduFp6iM1aKnUApzlML8BMOO1JlbXgN4aXaW3Uv9jNcqxI/a0jlftpMrQzP6T7QicUK3KWze7RGlrAtAtE2Q==",
"dev": true,
"requires": {
"moment": ">=2.14.0"
}
},
"@types/node": {
"version": "4.2.20",
"resolved": "https://registry.npmjs.org/@types/node/-/node-4.2.20.tgz",
@ -209,12 +218,6 @@
"integrity": "sha512-PBHCvO98hNec9A491vBbh0ZNDOVxccwKL1u2pm6fs9oDgm7SEnw0lEHqHfjsYryDxnE3zaf7LvERWEXjOp1hig==",
"dev": true
},
"@types/sjcl": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/@types/sjcl/-/sjcl-1.0.28.tgz",
"integrity": "sha1-RpPraUPjhehEpw+yW0aZ2yhschQ=",
"dev": true
},
"@webcomponents/shadycss": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@webcomponents/shadycss/-/shadycss-1.2.1.tgz",
@ -6645,8 +6648,7 @@
"moment-duration-format": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/moment-duration-format/-/moment-duration-format-2.2.2.tgz",
"integrity": "sha1-uVdhLeJgFsmtnrYIfAVFc+USd3k=",
"dev": true
"integrity": "sha1-uVdhLeJgFsmtnrYIfAVFc+USd3k="
},
"ms": {
"version": "2.0.0",
@ -7057,8 +7059,7 @@
"papaparse": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-4.3.5.tgz",
"integrity": "sha1-ts31yub+nsYDsb5m8RSmOsZFoDY=",
"dev": true
"integrity": "sha1-ts31yub+nsYDsb5m8RSmOsZFoDY="
},
"parents": {
"version": "1.0.1",
@ -8240,12 +8241,6 @@
"string-width": "^1.0.1"
}
},
"sjcl": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.7.tgz",
"integrity": "sha1-MrNlpQ3Ju6JriLo8nfjqNCF9n0U=",
"dev": true
},
"slice-ansi": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
@ -9059,9 +9054,9 @@
"dev": true
},
"typescript": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz",
"integrity": "sha1-A4qV99m7tCCxvzW6MdTFwd0//jQ=",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.3.tgz",
"integrity": "sha512-K7g15Bb6Ra4lKf7Iq2l/I5/En+hLIHmxWZGq3D4DIRNFxMNV6j2SHSvDOqs2tGd4UvD/fJvrwopzQXjLrT7Itw==",
"dev": true
},
"typical": {

View File

@ -14,9 +14,9 @@
"@types/chai": "^3.4.34",
"@types/core-js": "^0.9.35",
"@types/mocha": "^2.2.33",
"@types/moment-duration-format": "^2.2.0",
"@types/papaparse": "^4.1.28",
"@types/semver": "^5.3.33",
"@types/sjcl": "^1.0.27",
"archiver": "^1.2.0",
"bower": "^1.8.0",
"browserify": "^13.1.1",
@ -36,16 +36,13 @@
"karma-chrome-launcher": "^2.1.1",
"karma-mocha": "^1.3.0",
"mocha": "^3.4.2",
"moment-duration-format": "^2.2.2",
"papaparse": "^4.1.2",
"polymer-analyzer": "^2.2.0",
"polymer-bundler": "^2.3.1",
"rimraf": "^2.5.4",
"semver": "^5.4.1",
"sjcl": "^1.0.7",
"st": "^1.2.0",
"tsify": "^2.0.3",
"typescript": "^2.1.4",
"typescript": "^2.8.3",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.7.0"
},
@ -59,6 +56,8 @@
"electron-updater": "^2.21.0",
"fs-extra": "^5.0.0",
"moment": "^2.21.0",
"moment-duration-format": "^2.2.2",
"papaparse": "^4.1.2",
"uuid": "^3.1.0",
"yargs": "^4.8.1",
"zxcvbn": "^4.4.2"

View File

@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"target": "es2017",
"module": "es2015",
"moduleResolution": "node",
"isolatedModules": false,
"noImplicitAny": true,
@ -13,15 +13,14 @@
"preserveConstEnums": true,
"suppressImplicitAnyIndexErrors": true,
"lib": ["es2017", "dom"],
"outDir": "./app/lib",
"declaration": true,
"declaration": false,
"sourceMap": true,
"pretty": true,
"experimentalDecorators": true,
"typeRoots": [
"./typings",
"./node_modules/@types"
]
"baseUrl": ".",
"paths": {
"*": ["typings/*"]
}
},
"include": [
"app/src/**/*.ts",

96
typings/polymer.d.ts vendored
View File

@ -1,96 +0,0 @@
/**
* @license
* Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
interface Constructor<T extends Base> {
new (...args: any[]): T;
}
/**
* An interface to match all Objects, but not primitives.
*/
interface Base {}
/**
* A subclass-factory style mixin that extends `superclass` with a new subclass
* that implements the interface `M`.
*/
type Mixin<M> =
<C extends Base>(superclass: Constructor<C>) => Constructor<M & C>;
/**
* The Polymer function and namespace.
*/
declare var Polymer: {
/**
* The "Polymer function" for backwards compatibility with Polymer 1.x.
*/
(definition: any): void;
/**
* A base class for Polymer custom elements that includes the
* `Polymer.MetaEffects`, `Polymer.BatchedEffects`, `Polymer.PropertyEffects`,
* etc., mixins.
*/
Element: PolymerElementConstructor;
ElementMixin: Mixin<PolymerElement>;
PropertyEffects: Mixin<PolymerPropertyEffects>;
BatchedEffects: Mixin<PolymerBatchedEffects>;
};
declare interface PolymerElementConstructor {
new(): PolymerElement;
readonly is: string;
readonly config: {
properties: any
}
}
declare class PolymerElement extends PolymerMetaEffects {
static finalized: boolean;
static finalize(): void;
static readonly is: string;
static readonly template: HTMLTemplateElement;
root: ShadowRoot;
ready(): void;
updateStyles(properties: string[]): void;
}
declare class PolymerPropertyEffects extends HTMLElement {
ready(): void;
linkPaths(to: string, from: string): void;
unlinkPaths(path: string): void;
notifyPath(path: string): void;
notifySplices(path: string, splices: any[]): void;
get(path: string|(string|number)[], root: any): any;
set(path: string|(string|number)[], value: any): void;
push(path: string, ...items: any[]): any;
pop(path: string): any;
}
declare class PolymerBatchedEffects extends PolymerPropertyEffects {
// _propertiesChanged(currentProps, changedProps, oldProps): void;
// _setPropertyToNodeFromAnnotation(node, prop, value): void;
// _setPropertyFromNotification(path, value, event): void;
// _setPropertyFromComputation(prop, value): void;
// _enqueueClient(client): void;
// _flushClients(): void;
setProperties(props: any): void;
}
declare class PolymerMetaEffects extends PolymerBatchedEffects {
// _clearPropagateEffects(): void;
// _createPropertyFromInfo(name: string, info): void;
// _setPropertyDefaults(properties): void;
}