├── .eslintignore ├── .babelrc ├── .jshintrc ├── CryptoSync_Banner.gif ├── static ├── images │ ├── thumb.png │ ├── mb │ │ ├── trayic_dark.png │ │ └── trayic_light.png │ └── icons │ │ ├── code.svg │ │ ├── star.svg │ │ ├── issue-opened.svg │ │ ├── trashcan.svg │ │ ├── heart.svg │ │ ├── gdrive_sl.svg │ │ ├── settings.svg │ │ ├── package.svg │ │ ├── clippy.svg │ │ ├── repo-forked.svg │ │ ├── octoface.svg │ │ ├── mark-github.svg │ │ ├── sync.svg │ │ ├── crypto.svg │ │ ├── CryptoSync.svg │ │ ├── CryptoSyncVault_sl.svg │ │ └── CryptoSyncvault.svg ├── fonts │ ├── Roboto-Bold.eot │ ├── Roboto-Bold.ttf │ ├── Roboto-Thin.eot │ ├── Roboto-Thin.ttf │ ├── Roboto-Black.eot │ ├── Roboto-Black.ttf │ ├── Roboto-Black.woff │ ├── Roboto-Bold.woff │ ├── Roboto-Italic.eot │ ├── Roboto-Italic.ttf │ ├── Roboto-Italic.woff │ ├── Roboto-Light.eot │ ├── Roboto-Light.ttf │ ├── Roboto-Light.woff │ ├── Roboto-Medium.eot │ ├── Roboto-Medium.ttf │ ├── Roboto-Medium.woff │ ├── Roboto-Regular.eot │ ├── Roboto-Regular.ttf │ ├── Roboto-Thin.woff │ ├── Roboto-Regular.woff │ ├── Roboto-BlackItalic.eot │ ├── Roboto-BlackItalic.ttf │ ├── Roboto-BlackItalic.woff │ ├── Roboto-BoldItalic.eot │ ├── Roboto-BoldItalic.ttf │ ├── Roboto-BoldItalic.woff │ ├── Roboto-LightItalic.eot │ ├── Roboto-LightItalic.ttf │ ├── Roboto-LightItalic.woff │ ├── Roboto-MediumItalic.eot │ ├── Roboto-MediumItalic.ttf │ ├── Roboto-ThinItalic.eot │ ├── Roboto-ThinItalic.ttf │ ├── Roboto-ThinItalic.woff │ └── Roboto-MediumItalic.woff ├── style │ ├── errorprompt.less │ ├── menubar.less │ ├── masterpassprompt.less │ ├── mixins.css │ ├── errorprompt.css │ ├── menubar.css │ ├── vault.less │ ├── masterpassprompt.css │ ├── settings.less │ ├── mixins.less │ ├── vault.css │ ├── settings.css │ ├── setup.css │ └── setup.less ├── errorprompt.html ├── js │ ├── menubar.js │ └── jquery.marquee.min.js ├── addaccountprompt.html ├── menubar.html ├── masterpassprompt.html └── vault.html ├── res ├── app-icons │ ├── CryptoSync256.png │ └── CryptoSync256.icns └── res.js ├── .csslintrc ├── test ├── data │ ├── rfile.json │ └── rfs.json └── ui │ └── test.js ├── .eslintrc ├── src ├── elements │ └── react │ │ ├── menubar.js │ │ ├── menubar.jsx │ │ ├── masterpassprompt.jsx │ │ └── masterpassprompt.js ├── _Vault.js ├── Account.js ├── _MasterPassKey.js ├── util.js ├── MasterPass.js ├── vault.js ├── watch.js ├── OAuth.js ├── Db.js └── synker.js ├── script ├── travis-build.sh └── logger.js ├── bower.json ├── .codeclimate.yml ├── .travis.yml ├── license ├── .gitignore ├── gulp ├── readme.md ├── gulpfile.js ├── init.js └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*{.,-}min.js 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true 3 | } 4 | -------------------------------------------------------------------------------- /CryptoSync_Banner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/CryptoSync_Banner.gif -------------------------------------------------------------------------------- /static/images/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/images/thumb.png -------------------------------------------------------------------------------- /static/fonts/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Bold.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Thin.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /res/app-icons/CryptoSync256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/res/app-icons/CryptoSync256.png -------------------------------------------------------------------------------- /static/fonts/Roboto-Black.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Black.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Black.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Bold.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-Italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Italic.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Italic.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Light.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Light.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Medium.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Medium.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Regular.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Thin.woff -------------------------------------------------------------------------------- /res/app-icons/CryptoSync256.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/res/app-icons/CryptoSync256.icns -------------------------------------------------------------------------------- /static/fonts/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-Regular.woff -------------------------------------------------------------------------------- /static/images/mb/trayic_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/images/mb/trayic_dark.png -------------------------------------------------------------------------------- /static/images/mb/trayic_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/images/mb/trayic_light.png -------------------------------------------------------------------------------- /static/fonts/Roboto-BlackItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-BlackItalic.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-BlackItalic.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-BoldItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-BoldItalic.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-BoldItalic.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-LightItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-LightItalic.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-LightItalic.woff -------------------------------------------------------------------------------- /static/fonts/Roboto-MediumItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-MediumItalic.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-ThinItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-ThinItalic.eot -------------------------------------------------------------------------------- /static/fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /static/fonts/Roboto-ThinItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-ThinItalic.woff -------------------------------------------------------------------------------- /.csslintrc: -------------------------------------------------------------------------------- 1 | --exclude-exts=.min.css 2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes 3 | -------------------------------------------------------------------------------- /static/fonts/Roboto-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hr/CryptoSync/master/static/fonts/Roboto-MediumItalic.woff -------------------------------------------------------------------------------- /test/data/rfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "0B0pJLMXieC-ma0R1b0xrS3J6Qk0", 3 | "name": "test.png", 4 | "mimeType": "image/png", 5 | "parents": [ 6 | "0AEpJLMXieC-mUk9PVA" 7 | ], 8 | "md5Checksum": "55162924022d63704f046e49202a7c4b", 9 | "path": "/Users/HR/GitHub/CryptoSync/test/CryptoSync/test.png" 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "rules": { 4 | "strict": 0, 5 | "semi": [2,"never"] 6 | }, 7 | "ecmaFeatures": { 8 | "blockBindings": true, 9 | "forOf": true, 10 | "jsx": true 11 | }, 12 | "env": { 13 | "browser": true, 14 | "node": true, 15 | "es6": true 16 | }, 17 | "plugins": [ 18 | "html" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /test/data/rfs.json: -------------------------------------------------------------------------------- 1 | { 2 | "0AEpJLMXieC-mUk9PVA": { 3 | "path": "/" 4 | }, 5 | "0B0pJLMXieC-makxNdTZwRHNZenc": { 6 | "id": "0B0pJLMXieC-makxNdTZwRHNZenc", 7 | "name": "test", 8 | "mimeType": "application/vnd.google-apps.folder", 9 | "parents": [ 10 | "0AEpJLMXieC-mUk9PVA" 11 | ], 12 | "webViewLink": "https://docs.google.com/folderview?id=0B0pJLMXieC-makxNdTZwRHNZenc&usp=drivesdk", 13 | "ownedByMe": true, 14 | "path": "/test" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /static/style/errorprompt.less: -------------------------------------------------------------------------------- 1 | // out: ./errorprompt.css, compress: true 2 | /* ErrorPrompt styles 3 | ========================================================================== 4 | */ 5 | @import (less) "mixins.less"; 6 | .container { 7 | display : flex; 8 | align-items : center; 9 | justify-content: center; 10 | } 11 | #errorprompt { 12 | margin-top: 2rem; 13 | max-width : 85%; 14 | } 15 | button { 16 | width : 40%; 17 | font-size: 0.8rem; 18 | } 19 | h1 { 20 | font-size : 0.8rem; 21 | font-weight: 300; 22 | } 23 | -------------------------------------------------------------------------------- /static/images/icons/code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /static/images/icons/star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/elements/react/menubar.js: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var FileList = React.createClass({displayName: "FileList", 4 | fileList: function(event){ 5 | // Add code to set FileList state accordingly (update when necessary) 6 | }, 7 | getInitialState: function(){ 8 | // Check for previous state (on the previous run of the program) 9 | }, 10 | componentWillMount: function(){ 11 | // Set data accordingly on change 12 | }, 13 | render: function(){ 14 | return ( 15 | // File list array UI 16 | null 17 | ); 18 | } 19 | }); 20 | 21 | React.render( 22 | // render the file list UI 23 | ); -------------------------------------------------------------------------------- /script/travis-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo $CC 4 | echo $CXX 5 | # export CXX=g++-4.8 6 | export TEST_RUN=true 7 | 8 | git clone https://github.com/creationix/nvm.git /tmp/.nvm 9 | source /tmp/.nvm/nvm.sh 10 | nvm install "$NODE_VERSION" 11 | nvm use "$NODE_VERSION" 12 | 13 | node --version 14 | npm --version 15 | 16 | npm install electron-packager -g 17 | npm install --no-optional 18 | 19 | npm test 20 | 21 | # if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then 22 | # export DISPLAY=:99.0 23 | # sh -e /etc/init.d/xvfb start 24 | # sleep 3 25 | # unset TEST_RUN 26 | # npm run xtest 27 | # fi 28 | -------------------------------------------------------------------------------- /src/elements/react/menubar.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | /** @jsx React.DOM */ 3 | 4 | var FileList = React.createClass({ 5 | fileList: function(event){ 6 | // Add code to set FileList state accordingly (update when necessary) 7 | }, 8 | getInitialState: function(){ 9 | // Check for previous state (on the previous run of the program) 10 | }, 11 | componentWillMount: function(){ 12 | // Set data accordingly on change 13 | }, 14 | render: function(){ 15 | return ( 16 | // File list array UI 17 | null 18 | ); 19 | } 20 | }); 21 | 22 | React.render( 23 | // render the file list UI 24 | ); 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CryptoSync", 3 | "version": "0.0.1", 4 | "homepage": "https://github.com/HR/CryptoSync", 5 | "authors": [ 6 | "Habib Rehman " 7 | ], 8 | "description": "End-to-end encryption cloud sync client", 9 | "keywords": [ 10 | "cloud", 11 | "encryption", 12 | "crypto", 13 | "client", 14 | "drive", 15 | "dropbox" 16 | ], 17 | "license": "MIT", 18 | "ignore": [ 19 | "**/.*", 20 | "node_modules", 21 | "bower_components", 22 | "test", 23 | "tests" 24 | ], 25 | "dependencies": { 26 | "normalize-css": "normalize.css#~3.0.3", 27 | "jquery": "~2.1.4" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | csslint: 3 | enabled: true 4 | duplication: 5 | enabled: true 6 | config: 7 | languages: 8 | - javascript 9 | exclude_fingerprints: 10 | - 555c80119b06560cd2e96eb4e4e91f26 11 | - a81ed3d8cb6b36bacb95a0ab40d09d78 12 | - 9af23dc9a75d6c11f28122e9f83e7309 13 | - faca6a53a5a4ae580279527e261dd1da 14 | - 144b552ca7471e150abb4ece59240e71 15 | eslint: 16 | enabled: true 17 | fixme: 18 | enabled: true 19 | ratings: 20 | paths: 21 | - "**.css" 22 | - "**.inc" 23 | - "**.js" 24 | - "**.jsx" 25 | - "**.module" 26 | - "**.php" 27 | - "**.py" 28 | - "**.rb" 29 | exclude_paths: 30 | - test/ 31 | -------------------------------------------------------------------------------- /static/images/icons/issue-opened.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /static/images/icons/trashcan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /static/images/icons/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /static/images/icons/gdrive_sl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/_Vault.js: -------------------------------------------------------------------------------- 1 | /** 2 | * _Vault.js 3 | * Vault (protected) class 4 | ******************************/ 5 | 6 | var Vault = (function () { 7 | const vault = new WeakMap() 8 | 9 | function Vault (data) { 10 | // var props = { 11 | // crypted: crypted, 12 | // path: path, 13 | // viv: viv, 14 | // authTag: authTag, 15 | // data: data 16 | // } 17 | vault.set(this, data) 18 | } 19 | 20 | Vault.prototype.get = function (other) { 21 | return vault.get(id) 22 | } 23 | 24 | Vault.prototype.set = function (id) { 25 | vault.set(id) 26 | } 27 | 28 | Vault.prototype.delete = function (id) { 29 | vault.delete(id) 30 | } 31 | 32 | Vault.prototype.has = function (id) { 33 | return vault.has(id) 34 | } 35 | 36 | return Vault 37 | }()) 38 | 39 | module.exports = Vault 40 | -------------------------------------------------------------------------------- /static/images/icons/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /static/images/icons/package.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/Account.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * Account.js 4 | * User accounts 5 | ******************************/ 6 | 7 | /** 8 | * Constructor 9 | * 10 | * @param {type}:string the cloud service provider 11 | * @param {name}:string the name of the authenticated user 12 | * @param {email}:string the email of the authenticated user 13 | * @param {profileImg}:string base64 encoded profile image 14 | * @param {qouta}:string the qouta of the authenticated user 15 | * @param {oauth}:object the authenticated oauth2Client 16 | */ 17 | function Account (type, name, email, profileImg, quota, oauth) { 18 | this.type = type 19 | this.name = name 20 | this.email = email 21 | this.profileImg = profileImg 22 | this.quota = quota 23 | this.oauth = oauth 24 | // TODO: Implement qouta functionality 25 | // this.qouta = qouta 26 | } 27 | 28 | module.exports = Account 29 | -------------------------------------------------------------------------------- /static/images/icons/clippy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /static/images/icons/repo-forked.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /static/errorprompt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Oops, an error occured... 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 |

14 |
15 | 16 | 17 |
18 |
19 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '5.8.0' 4 | 5 | git: 6 | depth: 3 7 | 8 | branches: 9 | only: 10 | - master 11 | 12 | # env: 13 | # - NODE_VERSION='5.8.0' 14 | 15 | matrix: 16 | include: 17 | - os: osx 18 | env: 19 | - NODE_VERSION=5.8.0 20 | - BUILD_OS_NAME=darwin 21 | # - os: linux 22 | # env: 23 | # - NODE_VERSION=5.8.0 24 | # - BUILD_OS_NAME=linux 25 | 26 | before_script: 27 | - chmod +x ./script/travis-build.sh 28 | - export NODE_VERSION=5.8.0 29 | - export TEST_RUN=true 30 | 31 | script: 32 | - ./script/travis-build.sh 33 | # - npm install --no-optional 34 | # - npm test 35 | 36 | after_success: 37 | - npm run coveralls 38 | - npm run codeclimate 39 | 40 | cache: 41 | apt: true 42 | directories: 43 | - node_modules 44 | 45 | notifications: 46 | email: 47 | on_success: never 48 | on_failure: change 49 | 50 | addons: 51 | apt: 52 | sources: 53 | - ubuntu-toolchain-r-test 54 | packages: 55 | - g++-4.8 56 | - xvfb 57 | -------------------------------------------------------------------------------- /static/images/icons/octoface.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /script/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * logger.js 4 | * Custom logger for debugging 5 | ******************************/ 6 | const winston = require('winston') 7 | const moment = require('moment') 8 | const fs = require('fs-extra') 9 | const path = require('path') 10 | 11 | let debugDir = path.join(__dirname,'/debug') 12 | fs.ensureDirSync(debugDir) 13 | winston.emitErrs = true 14 | const fileTransport = new (winston.transports.File)({ 15 | filename: `${debugDir}/CS_debug_${moment().format('DD.MM@HH:MM').trim()}.log`, 16 | handleExceptions: true, 17 | maxsize: 5242880, // 5MB 18 | colorize: false 19 | }) 20 | 21 | module.exports = (!process.env.TEST_RUN) ? new (winston.Logger)({ 22 | transports: [ 23 | new (winston.transports.Console)({ 24 | level: 'debug', 25 | handleExceptions: true, 26 | // timestamp: true, 27 | json: false, 28 | colorize: true 29 | }), 30 | fileTransport 31 | ], 32 | exitOnError: false 33 | }) : new (winston.Logger)({ 34 | transports: [ 35 | fileTransport 36 | ], 37 | exitOnError: false 38 | }) 39 | -------------------------------------------------------------------------------- /static/images/icons/mark-github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /src/_MasterPassKey.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * MasterPass.js 4 | * Provides a way to securely set and retrieve the MasterPass globally 5 | ******************************/ 6 | 7 | // private static class member 8 | // var MP = Symbol() 9 | // module.exports = class MasterPassKey { 10 | // static get() { 11 | // return this[MP] 12 | // } 13 | // static set(mp) { 14 | // this[MP] = mp 15 | // } 16 | // } 17 | 18 | const MasterPassKey = (function () { 19 | const mpk = new WeakMap() 20 | 21 | function MasterPassKey (key) { 22 | mpk.set(this, key) 23 | } 24 | 25 | MasterPassKey.prototype.get = function () { 26 | if (mpk.get(this) === undefined) { 27 | return new Error('MasterPassKey is not set') 28 | } else { 29 | return mpk.get(this) 30 | } 31 | } 32 | 33 | MasterPassKey.prototype.set = function (key) { 34 | if (key instanceof Buffer) { 35 | mpk.set(this, key) 36 | } else { 37 | throw new Error('MasterPassKey not a Buffer') 38 | } 39 | } 40 | 41 | MasterPassKey.prototype.delete = function (key) { 42 | mpk.delete(this) 43 | } 44 | 45 | return MasterPassKey 46 | }()) 47 | 48 | module.exports = MasterPassKey 49 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Habib Rehman (https://git.io/HR) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished TODO so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * util.js 4 | * Contains essential common utilities required 5 | ******************************/ 6 | const fs = require('fs') 7 | const path = require('path') 8 | 9 | exports.checkDirectorySync = function (dir) { 10 | return exports.checkFileSync(dir) 11 | } 12 | 13 | exports.checkFileSync = function (path) { 14 | try { 15 | fs.accessSync(path, fs.F_OK) 16 | } catch (err) { 17 | if (err.code === 'ENOENT') return false 18 | } 19 | return true 20 | } 21 | 22 | exports.streamToString = function (stream, callback) { 23 | const chunks = [] 24 | stream.on('data', (chunk) => { 25 | chunks.push(chunk) 26 | }) 27 | stream.on('error', function (err) { 28 | callback(err) 29 | }) 30 | stream.on('end', () => { 31 | callback(null, chunks.join('')) 32 | }) 33 | } 34 | 35 | exports.getParam = function (name, url) { 36 | name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') 37 | const paramRegex = new RegExp(`[\?&]${name}=([^&#]*)`) 38 | const results = paramRegex.exec(url) 39 | return (results === null) ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')) 40 | } 41 | 42 | exports.resolvePath = function (fpath, bpath = global.paths.home) { 43 | let relPath = path.dirname(fpath.replace(bpath, '')) 44 | return path.normalize(relPath) 45 | } 46 | -------------------------------------------------------------------------------- /static/js/menubar.js: -------------------------------------------------------------------------------- 1 | function resolveFileType (fileType) { 2 | switch (fileType) { 3 | case 'png': 4 | case 'jpg': 5 | case 'jpeg': 6 | case 'gif': 7 | case 'tif': 8 | fileType = 'image' 9 | break 10 | case 'docx': 11 | case 'rtf': 12 | case 'doc': 13 | 14 | fileType = 'word' 15 | break 16 | case 'html': 17 | case 'js': 18 | case 'css': 19 | case 'c': 20 | case 'cpp': 21 | case 'py': 22 | case 'ruby': 23 | case 'java': 24 | 25 | fileType = 'code' 26 | break 27 | case 'mp4': 28 | case 'mkv': 29 | case 'flv': 30 | fileType = 'video' 31 | break 32 | case 'mp4': 33 | case 'mkv': 34 | case 'flv': 35 | case 'doc': 36 | case 'gdoc': 37 | fileType = 'word' 38 | break 39 | case 'ppt': 40 | fileType = 'powerpoint' 41 | break 42 | case 'ai': 43 | case 'psd': 44 | case 'flv': 45 | fileType = 'vector' 46 | break 47 | case 'mp3': 48 | case 'flac': 49 | case 'wav': 50 | fileType = 'audio' 51 | break 52 | case 'tar': 53 | case 'zip': 54 | case 'gz': 55 | fileType = 'vector' 56 | break 57 | case 'tar': 58 | case 'zip': 59 | case 'gz': 60 | fileType = 'zip' 61 | break 62 | case 'pdf': 63 | fileType = 'pdf' 64 | break 65 | case 'XLS': 66 | case 'XLSM': 67 | case 'XLSX': 68 | fileType = 'excel' 69 | break 70 | default: 71 | fileType = 'file' 72 | } 73 | return fileType 74 | } 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # dev 7 | dest/ 8 | .cred 9 | test/specs 10 | test/render.js 11 | .env 12 | spec/ 13 | deprecated/ 14 | src/Vault_cl.js 15 | 16 | 17 | # Icon must end with two \r 18 | Icon 19 | 20 | # Thumbnails 21 | ._* 22 | 23 | # Files that might appear in the root of a volume 24 | .DocumentRevisions-V100 25 | .fseventsd 26 | .Spotlight-V100 27 | .TemporaryItems 28 | .Trashes 29 | .VolumeIcon.icns 30 | 31 | # Directories potentially created on remote AFP share 32 | .AppleDB 33 | .AppleDesktop 34 | Network Trash Folder 35 | Temporary Items 36 | .apdisk 37 | 38 | 39 | ### Node ### 40 | # Logs 41 | logs 42 | *.log 43 | npm-debug.log* 44 | 45 | # Runtime data 46 | pids 47 | *.pid 48 | *.seed 49 | 50 | # Directory for instrumented libs generated by jscoverage/JSCover 51 | lib-cov 52 | 53 | # Coverage directory used by tools like istanbul 54 | coverage 55 | 56 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 57 | .grunt 58 | 59 | # node-waf configuration 60 | .lock-wscript 61 | 62 | # Compiled binary addons (http://nodejs.org/api/addons.html) 63 | build/Release 64 | 65 | # Dependency directories 66 | node_modules 67 | jspm_packages 68 | 69 | # Optional npm cache directory 70 | .npm 71 | 72 | # Optional REPL history 73 | .node_repl_history 74 | 75 | ### Bower ### 76 | bower_components 77 | .bower-cache 78 | .bower-registry 79 | .bower-tmp 80 | 81 | # Other stuff to ignore 82 | /dist 83 | *.log 84 | .editorconfig 85 | .Debug 86 | src/elements/*.js 87 | debug 88 | backups/ 89 | *.app 90 | chromedriver* 91 | -------------------------------------------------------------------------------- /static/images/icons/sync.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 16 | 17 | -------------------------------------------------------------------------------- /static/images/icons/crypto.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 10 | 12 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /src/elements/react/masterpassprompt.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | /** @jsx React.DOM */ 3 | 4 | var defaultPanel = React.createClass({ 5 | render: function() { 6 | return ( 7 |
8 |
9 |

Unlock the Vault

10 |

Please enter your MasterPass to unlock the Vault

11 | 12 |

The Vault that contains all the secret keys for your encrypted data is encrypted using a Master Password - your MasterPass

13 |
14 | 15 | 18 |
19 | ); 20 | } 21 | }); 22 | 23 | var MPform = React.createClass({ 24 | propTypes: { 25 | masterpass: React.PropTypes.string.isRequired 26 | }, 27 | getInitialState: function() { 28 | return {masterpass: ''}; 29 | }, 30 | handleMasterPassChange: function(e) { 31 | this.setState({masterpass: e.target.value}); 32 | }, 33 | handleSubmit: function(e) { 34 | e.preventDefault(); 35 | var masterpass = this.state.masterpass; 36 | var sendMasterPass = function() { 37 | ipc.send('masterpass-submitted', masterpass); 38 | }; 39 | // TODO: call decrypt db function 40 | }, 41 | render: function() { 42 | return ( 43 |
44 |
45 | 49 | 50 |
51 | 52 |
53 | Forgot MasterPass? 54 |
55 | 56 |
57 | 58 |
59 |
60 | ); 61 | } 62 | }); 63 | 64 | var MPprompt = React.createClass({ 65 | render: function() { 66 | return ( 67 |
68 | Crypto.Sync Vault icon 69 |
70 | 71 |
72 |
73 | ); 74 | } 75 | }); 76 | -------------------------------------------------------------------------------- /gulp: -------------------------------------------------------------------------------- 1 | Script started on Thu Mar 17 22:21:55 2016 2 | [?25h[?25h]7;file://R.local/Users/HR/GitHub/CryptoSync% ]2;Habib@R]1;..ub/CryptoSync]7;file://R.local/Users/HR/GitHub/CryptoSync Habib@R:~/GitHub/CryptoSync|master⚡⇒ script gulpgulp         s  lls 3 | ]2;ls -G]1;lsCryptoSync_Banner.gif gulp package.json src 4 | bower.json gulpfile.js readme.md static 5 | bower_components index.js res test 6 | build license script typescript 7 | debug node_modules spec 8 | % ]2;Habib@R]1;..ub/CryptoSync]7;file://R.local/Users/HR/GitHub/CryptoSync Habib@R:~/GitHub/CryptoSync|master⚡⇒ wwhich node  9 | ]2;which node]1;which/Users/HR/.nvm/versions/node/v5.6.0/bin/node 10 | % ]2;Habib@R]1;..ub/CryptoSync]7;file://R.local/Users/HR/GitHub/CryptoSync Habib@R:~/GitHub/CryptoSync|master⚡⇒ tterm 11 | ]2;term]1;term% ]2;Habib@R]1;..ub/CryptoSync]7;file://R.local/Users/HR/GitHub/CryptoSync Habib@R:~/GitHub/CryptoSync|master⚡⇒  -------------------------------------------------------------------------------- /src/MasterPass.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * MasterPass.js 4 | * MasterPass functionality 5 | ******************************/ 6 | 7 | const crypto = require('./crypto') 8 | const logger = require('../script/logger') 9 | const Main = (process.env.TEST_RUN) ? null : require('../index') 10 | 11 | exports.Prompt = function (reset = false) { 12 | return new Promise(function (resolve, reject) { 13 | Main.MasterPassPrompt(reset, function (err, gotMP) { 14 | if (err) reject(err) 15 | if (gotMP) { 16 | resolve() 17 | } else { 18 | reject(new Error('Could not get MasterPass')) 19 | } 20 | }) 21 | }) 22 | } 23 | 24 | exports.check = function (masterpass, callback) { 25 | crypto.deriveMasterPassKey(masterpass, global.creds.mpsalt, function (err, mpkey, mpsalt) { 26 | // logger.verbose('checkMasterPass deriveMasterPassKey callback') 27 | if (err) { 28 | logger.error(`ERROR: deriveMasterPassKey failed, ${err.stack}`) 29 | return callback(err, null) 30 | } 31 | crypto.genPassHash(mpkey, global.creds.mpksalt, function (mpkhash) { 32 | // logger.verbose(`creds.mpkhash = ${global.creds.mpkhash}, mpkhash (of entered mp) = ${mpkhash}`) 33 | const MATCH = crypto.verifyPassHash(global.creds.mpkhash, mpkhash) // check if masterpasskey derived is correct 34 | logger.info(`MATCH: ${global.creds.mpkhash} (creds.mpkhash) === ${mpkhash} (mpkhash) = ${MATCH}`) 35 | return callback(null, MATCH, mpkey) 36 | }) 37 | }) 38 | } 39 | 40 | exports.set = function (masterpass, callback) { 41 | // TODO: decide whther to put updated masterpass instantly 42 | // logger.verbose(`setMasterPass() for ${masterpass}`) 43 | crypto.deriveMasterPassKey(masterpass, null, function (err, mpkey, mpsalt) { 44 | if (err) return callback(err) 45 | global.creds.mpsalt = mpsalt 46 | // logger.verbose(`\n global.creds.mpsalt = ${global.creds.mpsalt.toString('hex')}`) 47 | crypto.genPassHash(mpkey, null, function (mpkhash, mpksalt) { 48 | global.creds.mpkhash = mpkhash 49 | global.creds.mpksalt = mpksalt 50 | return callback(null, mpkey) 51 | // logger.verbose(`deriveMasterPassKey callback: \npbkdf2 mpkey = ${mpkey.toString('hex')},\nmpsalt = ${global.creds.mpsalt.toString('hex')},\nmpkhash = ${mpkhash},\nmpksalt = ${mpksalt}`) 52 | }) 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /src/vault.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * Vault.js 4 | * Vault functionality 5 | ******************************/ 6 | const moment = require('moment') 7 | const sutil = require('util') 8 | const logger = require('../script/logger') 9 | const crypto = require('./crypto') 10 | 11 | // function Vault(crypted, path, viv, data) { 12 | // this.crypted = encrypted 13 | // this.path = path 14 | // this.viv = viv 15 | // this.data = data 16 | // } 17 | 18 | exports.init = function (mpkey) { 19 | return new Promise(function (resolve, reject) { 20 | logger.verbose(`Vault.init invoked. Creating global vault obj & encrypting...`) 21 | crypto.genIV() 22 | .then(function (iv) { 23 | // logger.verbose(`crypto.genIvSalt callback.`) 24 | global.vault = {} 25 | global.vault.files = {} 26 | global.vault.creationDate = moment().format() 27 | global.creds.viv = iv 28 | // logger.verbose(`Encrypting using MasterPass = ${global.MasterPassKey.get().toString('hex')}, viv = ${global.creds.viv.toString('hex')}`) 29 | }) 30 | .then(() => { 31 | return exports.encrypt(mpkey) 32 | }) 33 | .then(() => { 34 | resolve() 35 | }) 36 | .catch((err) => { 37 | reject(err) 38 | }) 39 | }) 40 | } 41 | 42 | exports.decrypt = function (mpkey) { 43 | return new Promise(function (resolve, reject) { 44 | if (!mpkey) reject(new Error('No MasterPassKey passed')) 45 | crypto.decryptObj(global.paths.vault, mpkey, global.creds.viv, global.creds.authTag, function (err, vault) { 46 | if (err) { 47 | logger.error(`decryptObj ERR: ${err.stack}`) 48 | reject(err) 49 | } else { 50 | global.vault = vault 51 | logger.verbose(`Decrypted vault, vault's content is ${sutil.inspect(vault).substr(0, 30)}`) 52 | resolve() 53 | } 54 | }) 55 | }) 56 | } 57 | 58 | exports.encrypt = function (mpkey) { 59 | return new Promise(function (resolve, reject) { 60 | crypto.encryptObj(global.vault, global.paths.vault, mpkey, global.creds.viv, function (err, tag) { 61 | logger.verbose(`crypto.encryptObj invoked...`) 62 | if (err) { 63 | reject(err) 64 | } else { 65 | // logger.verbose(`Encrypted successfully with tag = ${tag.toString('hex')}, saving auth tag and closing mdb...`) 66 | global.creds.authTag = tag 67 | resolve(tag) 68 | } 69 | }) 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /static/images/icons/CryptoSync.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 20 | 21 | 22 | CryptoSync 23 | Created with Sketch. 24 | 33 | 34 | -------------------------------------------------------------------------------- /src/watch.js: -------------------------------------------------------------------------------- 1 | const sync = require('./sync') 2 | const logger = require('../script/logger') 3 | const chokidar = require('chokidar') 4 | const dotRegex = /\/\..+/g 5 | const fNameRegex = /[^/]+[A-z0-9]+\.[A-z0-9]+/g 6 | 7 | const watcher = chokidar.watch(global.paths.home, { 8 | ignored: dotRegex, 9 | persistent: true, 10 | ignoreInitial: true, 11 | alwaysStat: true 12 | }) 13 | 14 | 15 | watcher.on('add', (path, stats) => { 16 | if (dotRegex.test(path)) { 17 | // Ignore dot file 18 | logger.info(`IGNORE added file ${path}, stats.mtime = ${stats.mtime}`) 19 | watcher.unwatch(path) 20 | } else { 21 | // Queue up to encrypt and put 22 | let fileName = path.match(fNameRegex)[0] 23 | // let relPath = path.replace(global.paths.home, '') 24 | logger.info(`ADD added file ${fileName}, stats ${stats.mtime}`) 25 | 26 | sync.genID() 27 | .then((fileId) => { 28 | return createFileObj(fileId, fileName, path) 29 | }) 30 | .then((file) => { 31 | return sync.pushCryptQueue(file) 32 | }) 33 | .then((file) => { 34 | return sync.pushPutQueue(file) 35 | }) 36 | .then((file) => { 37 | logger.info(`Done encrypting ${file.name} (${file.id})`) 38 | }) 39 | .catch((err) => { 40 | logger.error(`Error occured while adding ${fileName}: 41 | ${err.stack}`) 42 | }) 43 | } 44 | }) 45 | 46 | watcher 47 | .on('change', (path, stats) => { 48 | if (dotRegex.test(path)) { 49 | // Ignore dot file 50 | logger.info(`IGNORE added file ${path}, stats ${stats.mtime}`) 51 | watcher.unwatch(path) 52 | } else { 53 | // Queue up to encrypt and put 54 | let fileName = path.match(fNameRegex)[0] 55 | logger.info(`File ${fileName} at ${path} has been changed, stats ${stats.mtime}}`) 56 | } 57 | }) 58 | .on('unlink', (path, stats) => logger.info(`File ${path} has been removed, stats ${stats}`)) 59 | .on('addDir', (path, stats) => logger.info(`Directory ${path} has been added, stats ${stats}`)) 60 | .on('unlinkDir', (path, stats) => logger.info(`Directory ${path} has been removed, stats ${stats}`)) 61 | .on('error', error => logger.error(`Watcher error: ${error}`)) 62 | .on('ready', () => { 63 | logger.info('Initial scan complete. Ready for changes') 64 | }) 65 | // .on('raw', (event, path, details) => { 66 | // logger.verbose('Raw event info:', event, path, details) 67 | // }) 68 | // 69 | -------------------------------------------------------------------------------- /src/OAuth.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * OAuth.js 4 | * Establish a authorised OAuth 2 client 5 | ******************************/ 6 | 7 | // const fs = require('fs') 8 | // const google = require('googleapis') 9 | const googleAuth = require('google-auth-library') 10 | const logger = require('../script/logger') 11 | const SCOPES = ['https://www.googleapis.com/auth/drive'] 12 | 13 | function OAuth (type) { 14 | // TODO: Check type and accordingly init oauth2 15 | this.type = type 16 | this.oauth2Client 17 | } 18 | 19 | OAuth.prototype.authorize = function (token, callback) { 20 | var self = this 21 | // Authorize a client with the loaded credentials, then call the 22 | // Drive API. 23 | 24 | // Google Drive Auth 25 | logger.verbose(`Google Drive auth initiated`) 26 | const auth = new googleAuth() 27 | self.oauth2Client = new auth.OAuth2(process.env.clientId_, process.env.clientSecret_, process.env.redirectUri_) 28 | 29 | if (!token) { 30 | getNewToken(self, callback) 31 | } else { 32 | logger.verbose(`TOKEN FOUND: ${token}`) 33 | self.oauth2Client.credentials = JSON.parse(token) 34 | callback() 35 | } 36 | } 37 | 38 | /** 39 | * Get and store new token after prompting for user authorization, and then 40 | * execute the given callback with the authorized OAuth2 client. 41 | * 42 | * @param {google.auth.OAuth2} this.oauth2Client The OAuth2 client to get token for. 43 | * @param {getEventsCallback} callback The callback to call with the authorized 44 | * client. 45 | */ 46 | function getNewToken (self, callback) { 47 | logger.verbose(`getNewToken`) 48 | const authUrl = self.oauth2Client.generateAuthUrl({ 49 | access_type: 'offline', 50 | scope: SCOPES 51 | }) 52 | // GO TO URL `authUrl` in BrowserWindow to auth user 53 | callback(authUrl) 54 | } 55 | 56 | OAuth.prototype.getToken = function (auth_code) { 57 | var self = this 58 | return new Promise(function (resolve, reject) { 59 | // Google Drive 60 | // logger.verbose(`getToken`) 61 | self.oauth2Client.getToken(auth_code, function (err, token) { 62 | if (err) { 63 | reject(new Error(`Error while trying to retrieve access token ${err}`)) 64 | throw err 65 | } 66 | logger.verbose(`Got the ACCESS_TOKEN: 67 | ${require('util').inspect(token, { depth: null })}`) 68 | self.oauth2Client.credentials = token 69 | resolve(token) 70 | }) 71 | }) 72 | } 73 | 74 | module.exports = OAuth 75 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![alt tag](CryptoSync_Banner.gif?raw=true "Crypto.Sync application banner") 2 | 3 | # Crypto.Sync [![Build Status](https://travis-ci.org/HR/CryptoSync.svg?branch=master)](https://travis-ci.org/HR/CryptoSync) [![Coverage Status](https://coveralls.io/repos/github/HR/CryptoSync/badge.svg?branch=master)](https://coveralls.io/github/HR/CryptoSync?branch=master) [![Code Climate](https://codeclimate.com/github/HR/CryptoSync/badges/gpa.svg)](https://codeclimate.com/github/HR/CryptoSync) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) 4 | 5 | > A cross-platform end-to-end encryption cloud sync client 6 | 7 | Crypto.Sync an end-to-end encryption cloud synchronisation client that simply manages the encryption of your cloud data for you. 8 | 9 | ## Status 10 | Crypto.Sync is currently in **Alpha** so use at your own risk. 11 | Almost all of the UI has been implemented but the core functionality is still a work in progress. 12 | 13 | ## Dev 14 | 15 | ### Install (dependencies) 16 | ``` 17 | $ npm install 18 | ``` 19 | 20 | ### Run 21 | 22 | ``` 23 | $ npm start 24 | ``` 25 | 26 | ### Build 27 | 28 | ``` 29 | $ npm run build 30 | ``` 31 | 32 | Builds the app for OS X, Linux *, and Windows *. 33 | 34 | \*(not tested yet) 35 | 36 | ## License 37 | The MIT License (MIT) 38 | 39 | Copyright (c) Habib Rehman (https://git.io/HR) 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy 42 | of this software and associated documentation files (the "Software"), to deal 43 | in the Software without restriction, including without limitation the rights 44 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 45 | copies of the Software, and to permit persons to whom the Software is 46 | furnished TODO so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in 49 | all copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 52 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 53 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 54 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 55 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 56 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 57 | THE SOFTWARE. 58 | -------------------------------------------------------------------------------- /static/images/icons/CryptoSyncVault_sl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | CryptoSync Vault icon 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 27 | 29 | 30 | -------------------------------------------------------------------------------- /src/elements/react/masterpassprompt.js: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var defaultPanel = React.createClass({displayName: "defaultPanel", 4 | render: function() { 5 | return ( 6 | React.createElement("div", {id: "panel-default current"}, 7 | React.createElement("header", null, 8 | React.createElement("h1", null, "Unlock the Vault"), 9 | React.createElement("p", null, "Please enter your MasterPass to unlock the Vault"), 10 | React.createElement("img", {class: "info", src: "../../static/images/icons/info.svg", alt: ""}), 11 | React.createElement("p", {class: "info"}, "The Vault that contains all the secret keys for your encrypted data is encrypted using a Master Password - your MasterPass") 12 | ), 13 | React.createElement(MPform, null), 14 | React.createElement("footer", null, 15 | React.createElement("a", {href: "#", class: "navigationLink", "data-target": "shares"}, "Got shares?") 16 | ) 17 | ) 18 | ); 19 | } 20 | }); 21 | 22 | var MPform = React.createClass({displayName: "MPform", 23 | propTypes: { 24 | masterpass: React.PropTypes.string.isRequired 25 | }, 26 | getInitialState: function() { 27 | return {masterpass: ''}; 28 | }, 29 | handleMasterPassChange: function(e) { 30 | this.setState({masterpass: e.target.value}); 31 | }, 32 | handleSubmit: function(e) { 33 | e.preventDefault(); 34 | var masterpass = this.state.masterpass; 35 | var sendMasterPass = function() { 36 | ipc.send('masterpass-submitted', masterpass); 37 | }; 38 | // TODO: call decrypt db function 39 | }, 40 | render: function() { 41 | return ( 42 | React.createElement("form", {onSubmit: this.handleSubmit}, 43 | React.createElement("div", {class: "masterpass"}, 44 | React.createElement("input", {type: "password", name: "masterpass", class: "", placeholder: "********", 45 | value: this.state.masterpass, 46 | onChange: this.handleMasterPassChange} 47 | ), 48 | React.createElement("label", {for: "password"}, "INCORRECT MASTER PASSWORD") 49 | ), 50 | 51 | React.createElement("div", {class: "forgotMP"}, 52 | React.createElement("a", {class: "navigationLink", "data-target": "reset"}, "Forgot MasterPass?") 53 | ), 54 | 55 | React.createElement("div", {class: "submit"}, 56 | React.createElement("input", {type: "submit", value: "Unlock"}) 57 | ) 58 | ) 59 | ); 60 | } 61 | }); 62 | 63 | var MPprompt = React.createClass({displayName: "MPprompt", 64 | render: function() { 65 | return ( 66 | React.createElement("section", {id: "masterpassprompt"}, 67 | React.createElement("img", {src: "images/icons/CryptoSyncVault.svg", alt: "Crypto.Sync Vault icon", id: "vault"}), 68 | React.createElement("div", {class: "panel-container"}, 69 | React.createElement("defaultPanel", null) 70 | ) 71 | ) 72 | ); 73 | } 74 | }); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const shell = require('gulp-shell') 3 | 4 | gulp.task('default', shell.task([ 5 | // Absolute path '/usr/local/lib/node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron .' 6 | // Run electron 7 | // TODO: add compile less bash command > "for i in static/style/*.less do lessc $i ${i:0:${#i} - 5}.css done" 8 | // 'ELECTRON_RUN_AS_NODE=true node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron node_modules/node-inspector/bin/inspector.js' 9 | 'unset TEST_RUN && node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron --debug=5858 .' 10 | // 'node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron --debug-brk=5858 .' 11 | ])) 12 | 13 | gulp.task('rebuildni', shell.task([ 14 | // start node inspector server 15 | 'node_modules/.bin/node-pre-gyp --target=$(node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron -v | sed s/\v//g) --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall && node_modules/.bin/node-pre-gyp --target=$(node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron -v | sed s/\v//g) --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall' 16 | ])) 17 | 18 | gulp.task('buildnative', shell.task([ 19 | // start build the native module 20 | './node_modules/.bin/electron-rebuild #1' 21 | ])) 22 | 23 | gulp.task('ni', shell.task([ 24 | // start node inspector server 25 | 'ELECTRON_RUN_AS_NODE=true node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron node_modules/node-inspector/bin/inspector.js' 26 | ])) 27 | 28 | gulp.task('driver', shell.task([ 29 | // Run chromedriver 30 | './node_modules/chromedriver/bin/chromedriver' 31 | ])) 32 | 33 | gulp.task('test', shell.task([ 34 | // Run test stuff 35 | "mocha --compilers js:babel-core/register test/" 36 | ])) 37 | 38 | gulp.task('ntest', shell.task([ 39 | // Run test stuff 40 | 'mocha --reporter nyan --compilers js:babel-core/register' 41 | ])) 42 | 43 | gulp.task('cov', shell.task([ 44 | // Run test stuff 45 | './node_modules/.bin/babel-node ./node_modules/.bin/isparta cover --root src/ ./node_modules/.bin/_mocha' 46 | ])) 47 | 48 | gulp.task('lcov', shell.task([ 49 | // Run test stuff 50 | './node_modules/.bin/babel-node ./node_modules/.bin/isparta cover --root src/ ./node_modules/.bin/_mocha --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js' 51 | ])) 52 | 53 | gulp.task('watch', function () { 54 | gulp.watch(['./static/**/*', './*.js'], ['run']) 55 | }) 56 | 57 | gulp.task('run', function () { 58 | return gulp.src('*', { 59 | read: false 60 | }) 61 | .pipe(shell([ 62 | // start electron main and render process 63 | 'node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron .' 64 | ])) 65 | }) 66 | 67 | gulp.task('lint', function () { 68 | return gulp.src('*', { 69 | read: false 70 | }) 71 | .pipe(shell([ 72 | // lint 73 | 'eslint src/*.js src/*/*.js *.js' 74 | ])) 75 | }) 76 | -------------------------------------------------------------------------------- /static/images/icons/CryptoSyncvault.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | CryptoSync 8 | Created with Sketch. 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 42 | 43 | -------------------------------------------------------------------------------- /init.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * init.js 4 | * Initialisers 5 | ******************************/ 6 | const _ = require('lodash') 7 | const moment = require('moment') 8 | const fs = require('fs-extra') 9 | const google = require('googleapis') 10 | const logger = require('./script/logger') 11 | const Db = require('./src/Db') 12 | 13 | exports.main = function () { 14 | // Decrypt db (the Vault) and get ready for use 15 | // open mdb 16 | logger.verbose(`PROMISE: Main initialisation`) 17 | return new Promise(function (resolve, reject) { 18 | global.mdb = new Db(global.paths.mdb) 19 | global.mdb.get('creds', function (err, json) { 20 | if (err) { 21 | if (err.notFound) { 22 | logger.error(`ERROR: key creds NOT FOUND `) 23 | global.creds = {} 24 | reject(err) 25 | } else { 26 | // I/O or other error, pass it up the callback 27 | logger.error(`ERROR: mdb.get('creds') FAILED`) 28 | reject(err) 29 | } 30 | } else { 31 | logger.info(`SUCCESS: creds FOUND ${json.substr(0, 20)}`) 32 | global.creds = JSON.parse(json) 33 | setTimeout(function () { 34 | logger.verbose(`resolve global.creds called`) 35 | resolve() 36 | }, 0) 37 | } 38 | }) 39 | fs.ensureDir(global.paths.home, function (err) { 40 | if (err) reject(err) 41 | resolve() 42 | }) 43 | }) 44 | } 45 | 46 | exports.setup = function () { 47 | logger.verbose(`PROMISE: Setup initialisation`) 48 | return new Promise(function (resolve, reject) { 49 | global.mdb = new Db(global.paths.mdb) 50 | fs.ensureDir(global.paths.home, function (err) { 51 | if (err) reject(err) 52 | resolve() 53 | }) 54 | }) 55 | } 56 | 57 | exports.drive = function (gAuth, notInstOfAuth) { 58 | // store auth token in mdb 59 | logger.verbose(`init.drive: `) 60 | // logger.verbose(require('util').inspect(gAuth, { depth: null })) 61 | return new Promise(function (resolve, reject) { 62 | if (notInstOfAuth) { 63 | const initedGAuth = new google.auth.OAuth2(gAuth.clientId_, gAuth.clientSecret_, gAuth.redirectUri_) 64 | initedGAuth.setCredentials(gAuth.credentials) 65 | global.drive = google.drive({ 66 | version: 'v3', 67 | auth: initedGAuth 68 | }) 69 | resolve() 70 | } else { 71 | global.drive = google.drive({ 72 | version: 'v3', 73 | auth: gAuth.oauth2Client 74 | }) 75 | resolve() 76 | } 77 | }) 78 | } 79 | 80 | exports.stats = function () { 81 | return new Promise(function (resolve, reject) { 82 | global.stats.startTime = moment().format() 83 | global.stats.time = moment() 84 | resolve() 85 | }) 86 | } 87 | 88 | exports.syncGlobals = function (trees) { 89 | return new Promise(function (resolve, reject) { 90 | logger.verbose(`Saving file tree (fBtree) to global.state.toGet`) 91 | global.state = {} 92 | global.state.toGet = _.flattenDeep(trees[0]) 93 | global.state.toCrypt = [] 94 | global.state.toUpdate = [] 95 | global.state.recents = [] 96 | global.state.rfs = trees[1] 97 | resolve() 98 | }) 99 | } 100 | -------------------------------------------------------------------------------- /static/style/menubar.less: -------------------------------------------------------------------------------- 1 | // out: ./menubar.css, compress: true 2 | /* 3 | Menubar styles 4 | ========================================================================== 5 | */ 6 | @import (less) "mixins.less"; 7 | 8 | /* theme colors */ 9 | @side-margin: 0.8rem; 10 | @tb-margin: 0.6rem; 11 | @fitem-margin-b: 2.4rem; 12 | @name-fsize: 0.8rem; 13 | @header-fsize: 0.8rem; 14 | @spacing04: 0.4rem; 15 | @spacing-ic-txt: @side-margin - 0.4rem; 16 | @lastSynced-fsize: 0.6rem; 17 | @ic-size: 1.2rem; 18 | @win-height: 15rem; 19 | @keyframes spin { 20 | 100% { 21 | -webkit-transform: rotate(360deg); 22 | transform : rotate(360deg); 23 | } 24 | } 25 | section#menubar { 26 | min-height : 100%; 27 | position : relative; 28 | background-color: @white; 29 | overflow : hidden; 30 | } 31 | header { 32 | clear : both; 33 | padding : @spacing04 0 @spacing04 @side-margin; 34 | margin : 0; 35 | font-size : @header-fsize; 36 | border-top : 1px solid @light; 37 | border-bottom: 1px solid @light; 38 | } 39 | .left { 40 | -webkit-align-self: flex-start; 41 | align-self : flex-start !important; 42 | } 43 | .right { 44 | margin-left: auto !important; 45 | } 46 | div.fileList { 47 | height : @win-height - @fitem-margin-b; 48 | width : 100%; 49 | overflow-y : auto; 50 | margin-bottom: @fitem-margin-b; 51 | } 52 | .spin { 53 | width : @ic-size; 54 | z-index : 0; 55 | -webkit-animation: spin 4s linear infinite; 56 | animation : spin 4s linear infinite; 57 | } 58 | div.content, 59 | div.type { 60 | display : inline-block; 61 | position: relative; 62 | } 63 | div.content { 64 | width: 80%; 65 | vertical-align: top; 66 | margin-left : @spacing-ic-txt; 67 | } 68 | div.name { 69 | font-size: @name-fsize; 70 | text-overflow: ellipsis; 71 | position: relative; 72 | overflow: hidden; 73 | width: 95%; 74 | } 75 | div.lastSynced { 76 | font-size: @lastSynced-fsize; 77 | } 78 | div.cloudType { 79 | position: absolute; 80 | bottom : -1px; 81 | right : -4px; 82 | } 83 | div.cloudType > img { 84 | height : 0.8rem; 85 | width : auto; 86 | opacity: 1; 87 | } 88 | img.fileType { 89 | width : 1.4rem; 90 | padding-left: @side-margin; 91 | margin : 0; 92 | } 93 | div.item { 94 | width: 100%; 95 | border-top: 1px solid @light; 96 | padding : @spacing04 0; 97 | } 98 | div.status { 99 | display : flex; 100 | display : -webkit-flex; 101 | align-items: center; 102 | left : 0; 103 | bottom : 0; 104 | } 105 | div.status > span { 106 | font-size: 0.9rem; 107 | } 108 | div.head { 109 | display : flex; 110 | display : -webkit-flex; 111 | align-items: center; 112 | } 113 | div.status > img { 114 | margin-right: @spacing-ic-txt !important; 115 | } 116 | footer { 117 | display : flex; 118 | clear : both; 119 | position : absolute; 120 | border-top : 1px solid @light; 121 | width : 100%; 122 | padding-bottom : 0; 123 | background-color: @white; 124 | bottom : 0; 125 | left : 0; 126 | } 127 | img.icon { 128 | height : @ic-size; 129 | display: inline; 130 | margin : @tb-margin @side-margin; 131 | } 132 | div.item:first-child { 133 | border-top: none !important; 134 | } 135 | -------------------------------------------------------------------------------- /static/style/masterpassprompt.less: -------------------------------------------------------------------------------- 1 | // out: ./masterpassprompt.css, compress: true 2 | /* 3 | MasterPassPrompt styles 4 | ========================================================================== 5 | */ 6 | @import (less) "mixins.less"; 7 | 8 | /* Variable declarations*/ 9 | @invalid-color: #9F3A38; 10 | 11 | /* Section styles */ 12 | header { 13 | margin: 0; 14 | } 15 | header > p { 16 | color: @blacker; 17 | } 18 | h1 { 19 | font-size : 1.4rem; 20 | margin-bottom: 0.1rem; 21 | } 22 | p { 23 | margin: 0; 24 | } 25 | a { 26 | font-size : 0.8rem; 27 | color : @blacker; 28 | text-decoration: none; 29 | outline : none; 30 | } 31 | #masterpassprompt { 32 | height : 100%; 33 | min-height : 20rem; 34 | width : 100%; 35 | background-color: @white; 36 | text-align : center; 37 | overflow : hidden; 38 | } 39 | #vault { 40 | width : 7rem; 41 | height: auto; 42 | margin: 2rem auto 0; 43 | } 44 | .panel-container { 45 | position: relative; 46 | } 47 | .panel-container > div { 48 | display : block; 49 | position : absolute; 50 | text-align: center; 51 | padding : 0 3rem 3rem; 52 | transform : translateX(-100%); 53 | transition: transform 0.3s; 54 | } 55 | .panel-container > div.current ~ div { 56 | transform: translateX(100%); 57 | } 58 | .panel-container > div.current { 59 | transform: none; 60 | position : relative; 61 | } 62 | p.info { 63 | display : block; 64 | width : 100%; 65 | box-sizing : border-box; 66 | max-height : 0; 67 | overflow : hidden; 68 | padding : 0 0.5rem; 69 | transition : max-height 0.3s, padding 0.3s; 70 | background-color: #efefef; 71 | font-size : 0.8rem; 72 | } 73 | img.info { 74 | float : right; 75 | height: 0.9rem; 76 | } 77 | img.info:hover + p.info { 78 | max-height : 10rem; 79 | padding-top : 0.5rem; 80 | padding-bottom: 0.5rem; 81 | } 82 | div.masterpass > input { 83 | width: 98%; 84 | } 85 | input[type=password] { 86 | margin-top : 1rem; 87 | border : none; 88 | border-bottom: 1px solid @light; 89 | outline : none; 90 | &:focus { 91 | animation-name : colorTrans; 92 | animation-duration: 2s; 93 | border-bottom : 1px solid @black; 94 | } 95 | } 96 | .invalid { 97 | border-color: @invalid-color !important; 98 | } 99 | a.back { 100 | float: left; 101 | } 102 | a.back >img { 103 | height: 1rem; 104 | width : auto; 105 | } 106 | div.forgotMP { 107 | padding : 0.2rem 0.2rem 0 0; 108 | text-align: right; 109 | } 110 | input[type=submit] { 111 | margin-top : 1rem; 112 | height : 2rem; 113 | font-weight : normal; 114 | background-color: @white; 115 | border : 1px solid @light; 116 | width : 100%; 117 | outline : none; 118 | &:active, 119 | &:hover { 120 | background-color: @light; 121 | } 122 | } 123 | div.submit { 124 | text-align : right; 125 | background-color: @white; 126 | width : 100%; 127 | } 128 | footer { 129 | display : flex; 130 | clear : both; 131 | position : absolute; 132 | border-top : 1px solid @light; 133 | width : 100%; 134 | padding-bottom : 0; 135 | background-color: @white; 136 | bottom : 0; 137 | left : 0; 138 | } 139 | footer > a { 140 | float : right; 141 | padding: 0.2rem; 142 | } 143 | a.back { 144 | float: left; 145 | } 146 | a.back >img { 147 | height: 1rem; 148 | width : auto; 149 | } 150 | 151 | /* INVALID STYLING */ 152 | div.masterpass > label { 153 | display : inline-block; 154 | font-size: 0.8rem; 155 | margin : 0.2rem 0; 156 | color : @invalid-color; 157 | } 158 | -------------------------------------------------------------------------------- /src/Db.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * Db.js 4 | * Custom DB (levelup) API implementation 5 | ******************************/ 6 | 7 | const levelup = require('levelup') 8 | const _ = require('lodash') 9 | const logger = require('../script/logger') 10 | const util = require('util') 11 | 12 | function Db (location) { 13 | // Initialize necessary methods/properties from levelup in this instance 14 | levelup.call(this, location) 15 | } 16 | 17 | // Inherit functions from levelup's prototype 18 | util.inherits(Db, levelup) 19 | 20 | Db.prototype.saveGlobalObj = function (objName) { 21 | const self = this 22 | // logger.verbose(`PROMISE: saveGlobalObj for ${objName}`) 23 | return new Promise(function (resolve, reject) { 24 | if (!(_.isEmpty(global[objName]))) { 25 | self.put(objName, JSON.stringify(global[objName]), function (err) { 26 | if (err) { 27 | logger.verbose(`ERROR: mdb.put('${objName}') failed, ${err}`) 28 | // I/O or other error, pass it up the callback 29 | reject(err) 30 | } 31 | // logger.verbose(`SUCCESS: mdb.put('${objName}')`) 32 | resolve() 33 | }) 34 | } else { 35 | // logger.verbose('Nothing to save; empty.') 36 | resolve() 37 | } 38 | }) 39 | } 40 | 41 | Db.prototype.restoreGlobalObj = function (objName) { 42 | const self = this 43 | // logger.verbose(`PROMISE: restoreGlobalObj for ${objName}`) 44 | return new Promise(function (resolve, reject) { 45 | self.get(objName, function (err, json) { 46 | if (err) { 47 | if (err.notFound) { 48 | logger.verbose(`ERROR: Global obj ${objName} NOT FOUND `) 49 | reject(err) 50 | } else { 51 | // I/O or other error, pass it up the callback 52 | logger.verbose(`ERROR: mdb.get('${objName}') FAILED`) 53 | reject(err) 54 | } 55 | } else { 56 | // logger.verbose(`SUCCESS: ${objName} FOUND`) 57 | try { 58 | global[objName] = JSON.parse(json) || {} 59 | resolve() 60 | } catch (e) { 61 | return e 62 | } 63 | } 64 | }) 65 | }) 66 | } 67 | 68 | Db.prototype.onlyGetValue = function (key) { 69 | const self = this 70 | logger.verbose(`PROMISE: getValue for getting ${key}`) 71 | return new Promise(function (resolve, reject) { 72 | self.get(key, function (err, value) { 73 | if (err) { 74 | if (err.notFound) { 75 | logger.verbose(`ERROR: key ${key} NOT FOUND `) 76 | resolve(null) 77 | } else { 78 | // I/O or other error, pass it up the callback 79 | logger.verbose(`ERROR: mdb.get('${key}') FAILED`) 80 | reject(err) 81 | } 82 | } else { 83 | logger.verbose(`SUCCESS: ${key} FOUND`) 84 | resolve(value) 85 | } 86 | }) 87 | }) 88 | } 89 | 90 | Db.prototype.getValue = function (key) { 91 | const self = this 92 | logger.verbose(`PROMISE: getValue for getting ${key}`) 93 | return new Promise(function (resolve, reject) { 94 | self.get(key, function (err, value) { 95 | if (err) { 96 | if (err.notFound) { 97 | resolve(null) 98 | } else { 99 | // I/O or other error, pass it up the callback 100 | logger.verbose(`ERROR: mdb.get('${key}') FAILED`) 101 | reject(err) 102 | } 103 | } else { 104 | logger.verbose(`SUCCESS: ${key} FOUND`) 105 | resolve(value) 106 | } 107 | }) 108 | }) 109 | } 110 | 111 | Db.prototype.storeToken = function (token) { 112 | const self = this 113 | return new Promise(function (resolve, reject) { 114 | self.put(`gdrive-token`, JSON.stringify(token), function (err) { 115 | if (err) reject(err) // some kind of I/O error 116 | logger.verbose(`Token stored in mdb`) 117 | resolve() 118 | }) 119 | }) 120 | } 121 | 122 | module.exports = Db 123 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Crypto.Sync", 3 | "productName": "CryptoSync", 4 | "version": "0.2.0", 5 | "description": "A cross-platform end-to-end encryption cloud sync client", 6 | "license": "MIT", 7 | "repository": "https://github.com/HR/CryptoSync", 8 | "homepage": "https://github.com/HR/CryptoSync", 9 | "bugs": "https://github.com/HR/CryptoSync/issues", 10 | "author": { 11 | "name": "Habib Rehman", 12 | "email": "Habib.R@outlook.com", 13 | "url": "https://git.io/HR" 14 | }, 15 | "engines": { 16 | "node": ">=4" 17 | }, 18 | "scripts": { 19 | "electronVersion": "node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron -v | sed s/\\v//g", 20 | "test": "TEST_RUN=true mocha --compilers js:babel-core/register test/test.js", 21 | "xtest": "unset TEST_RUN && npm run xbuild && mocha --compilers js:babel-core/register ./test/ui/*.js", 22 | "xbuild": "npm_package_productName=CryptoSyncTest && electron-packager . $npm_package_productName --out=dest --ignore='(test|dest|coverage|backups)' --asar=false --platform=darwin --arch=x64 --version=$(npm run electronVersion) --icon=res/app-icons/CryptoSync256.icns --app-copyright=HR --overwrite && npm run productNameChange", 23 | "coverage": "TEST_RUN=true ./node_modules/.bin/babel-node ./node_modules/.bin/isparta cover --root src/ ./node_modules/.bin/_mocha -- test/test.js --reporter mocha-lcov-reporter", 24 | "precoveralls": "TEST_RUN=true npm run coverage", 25 | "coveralls": "node ./node_modules/.bin/coveralls < coverage/lcov.info", 26 | "codeclimate": "node ./node_modules/.bin/codeclimate-test-reporter < coverage/lcov.info", 27 | "productNameChange": "perl -pi -e 's/\"CryptoSync\"/\"CryptoSyncTest\"/g' ./dest/CryptoSyncTest-darwin-x64/CryptoSyncTest.app/Contents/Resources/app/package.json && perl -pi -e 's/CryptoSync/CryptoSyncTest/g' ./dest/CryptoSyncTest-darwin-x64/CryptoSyncTest.app/Contents/Resources/app/index.js", 28 | "start": "./node_modules/gulp/bin/gulp.js", 29 | "testbuild": "electron-packager . $npm_package_productName --out=dest --ignore='(test|dest|coverage)' --asar=false --platform=$BUILD_OS_NAME --arch=x64 --version=$(npm run electronVersion) --icon=res/app-icons/CryptoSync256 --app-copyright=HR --overwrite", 30 | "build": "electron-packager . $npm_package_productName --out=dest --ignore='(test|dest|coverage)' --prune --asar --all --version=$(npm run electronVersion)" 31 | }, 32 | "xo": { 33 | "esnext": true 34 | }, 35 | "keywords": [ 36 | "cloud", 37 | "sync", 38 | "encryption", 39 | "crypto", 40 | "end-to-end", 41 | "client", 42 | "drive", 43 | "dropbox" 44 | ], 45 | "dependencies": { 46 | "async": "*", 47 | "babel-core": "*", 48 | "base64-stream": "*", 49 | "buffer": "^4.5.1", 50 | "chokidar": "*", 51 | "coveralls": "^2.11.9", 52 | "dotenv": "^2.0.0", 53 | "electron-debug": "*", 54 | "electron-positioner": "*", 55 | "electron-prebuilt": "^0.37.5", 56 | "estraverse": "^4.2.0", 57 | "fs-extra": "*", 58 | "fstream": "*", 59 | "google-auth-library": "*", 60 | "googleapis": "*", 61 | "handlebars": "*", 62 | "jquery": "*", 63 | "level-js": "*", 64 | "leveldown": "*", 65 | "levelup": "*", 66 | "lodash": "*", 67 | "mocha": "^2.4.5", 68 | "moment": "*", 69 | "secrets.js": "*", 70 | "tar": "*", 71 | "urlsafe-base64": "^1.0.0", 72 | "winston": "^2.2.0" 73 | }, 74 | "devDependencies": { 75 | "babel-cli": "^6.6.5", 76 | "babel-eslint": "*", 77 | "babel-preset-es2015": "*", 78 | "chai": "*", 79 | "chai-as-promised": "^5.3.0", 80 | "codeclimate-test-reporter": "^0.3.1", 81 | "coveralls": "^2.11.9", 82 | "electron-packager": "*", 83 | "eslint": "*", 84 | "eslint-plugin-html": "*", 85 | "gulp": "*", 86 | "gulp-shell": "*", 87 | "isparta": "^4.0.0", 88 | "jshint": "*", 89 | "mocha-lcov-reporter": "^1.2.0", 90 | "spectron": "^1.37.0", 91 | "standard": "^6.0.8", 92 | "wdio-mocha-framework": "^0.2.12", 93 | "xo": "*" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /res/res.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * res.js 4 | * Required static resources 5 | ******************************/ 6 | 7 | exports.thumbnail = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABj1BMVEUzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzOXLK+IAAAAhHRSTlMAAQIDBAYHCAkKCw0OEBETFBUWFxgZGhscHR4fIiMkJSouLzAxMjM1ODo7PEBGTFJVV1lbXl9gY2RlZm56fH+BhYeLjY6PlJWWmJuhpKWrra6vsbK6vb/DysvMzc/Q0dLT1NXW2Nrc3d7f4OHj5OXn6ers7e7v8PLz9PX29/j5+vv8/f6Dg90RAAACyklEQVR4AaXXC3uSZRzH8Z/bmG1D1wpJW4gH6VDqPGuOiIkKJeQ8oIHNtAAHOq0UmaZo8n3hpdsV3M/98IDcnxdwXxc8/8Pvr37ip5culxrNVqvZKF1eOh3Xezl0odrB0KleOKQh7UhWAGg3ioVcJpMrFBttACrJHRosknkGUEovRCe0aSK6kC4BPMtENMDiE6Ca2iPLnlQVeLKoIPtvAuXjW+Rry/EycHO/+jrbgYenFODUQ+icVR8XgUuzCjR7CbgoX1egfUwDHWvDFfm4Dqt7NYS9q3Bdlqtwe05DmbsNV+WRhbvTGtL0XcjKcAbWtmto29fgjHrshtdxmWb3fX5gUyLxsUzx17BbXStwVIbpH5/T4+VP8zIchZWe+oW8DFO/4vGHp5HysKhN4Rc83SrDEpZlGbY+5UVYG87DCRnG1wBWa/feqdXeAMzJcALO651tr6jIFH4JLIz9b18L+FqmCq+26a0kHJFpZh3aIXXdAb6S6Qgk9dZ9HshjpgXtqLp+A76UxwPu6z8HIeX7wCfq+t3vgRQc3Gji2GgPxDYau8YteYWfwz+fqqsKfCOvW9SkOKTtbgH4SF1/Al/IKw1xnYTDsnz3y8r36vHtz3d+CMnrMJzUOTpRjSja4ZyWqWtkdZZVpqiRFSmrQcGavB/2YU3sAg01yckwce3vvq5NyJCjqXUyMuwkwE4ZMqw7P+D8E5z/RPfP6FpIfqU8M/WBr6kZn1K2m2ks33r8l6/HrfyY1Ux2O0cJELXa2R4ouwiwyxoo9kgL3XjT142QNdL8hmos9pmvWMweqtZYD2SPdWuxDGYvFnu1TY6P+RqftFab73LNPqrf81V/lLWXq73eIwSI2OvdChjzBJi3A4YVcSZL9FWatCOOHbJCicQBX4lEyA5Z7jHPPWi6R133sO0e990PDveTx/3ocj/73A9P99PX5fh2OP//BQHs8YyRMT3dAAAAAElFTkSuQmCC' 8 | exports.urlsafe_thumb = 'aVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUVBQUFBQkFDQU1BQUFDZHQ0SHNBQUFCajFCTVZFVXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek16TXpNek9YTEsrSUFBQUFoSFJTVGxNQUFRSURCQVlIQ0FrS0N3ME9FQkVURkJVV0Z4Z1pHaHNjSFI0ZklpTWtKU291THpBeE1qTTFPRG83UEVCR1RGSlZWMWxiWGw5Z1kyUmxabTU2ZkgrQmhZZUxqWTZQbEpXV21KdWhwS1dycmE2dnNiSzZ2Yi9EeXN2TXpjL1EwZExUMU5YVzJOcmMzZDdmNE9IajVPWG42ZXJzN2U3djhQTHo5UFgyOS9qNSt2djgvZjZEZzkwUkFBQUN5a2xFUVZSNEFhWFhDM3VTWlJ6SDhaL2JtRzFEMXdwSlc0Z0g2VkRxUEd1T2lJa0tKZVE4b0lITnRBQUhPcTBVbWFabzhuM2hwZHNWM00vOThJRGNueGR3WHhjOC84UHZyMzdpcDVjdWx4ck5WcXZaS0YxZU9oM1hlemwwb2RyQjBLbGVPS1FoN1VoV0FHZzNpb1ZjSnBNckZCdHRBQ3JKSFJvc2tua0dVRW92UkNlMGFTSzZrQzRCUE10RU5NRGlFNkNhMmlQTG5sUVZlTEtvSVB0dkF1WGpXK1JyeS9FeWNITy8ranJiZ1llbkZPRFVRK2ljVlI4WGdVdXpDalI3Q2Jnb1gxZWdmVXdESFd2REZmbTREcXQ3TllTOXEzQmRscXR3ZTA1RG1ic05WK1dSaGJ2VEd0TDBYY2pLY0FiV3RtdG8yOWZnakhyc2h0ZHhtV2IzZlg1Z1V5THhzVXp4MTdCYlhTdHdWSWJwSDUvVDQrVlA4ekljaFpXZStvVzhERk8vNHZHSHA1SHlzS2hONFJjODNTckRFcFpsR2JZKzVVVllHODdEQ1JuRzF3QldhL2ZlcWRYZUFNekpjQUxPNjUxdHI2aklGSDRKTEl6OWIxOEwrRnFtQ3ErMjZhMGtISkZwWmgzYUlYWGRBYjZTNlFnazlkWjlIc2hqcGdYdHFMcCtBNzZVeHdQdTZ6OEhJZVg3d0NmcSt0M3ZnUlFjM0dqaTJHZ1B4RFlhdThZdGVZV2Z3eitmcXFzS2ZDT3ZXOVNrT0tUdGJnSDRTRjEvQWwvSUt3MXhuWVREc256M3k4cjM2dkh0ejNkK0NNbnJNSnpVT1RwUmpTamE0WnlXcVd0a2RaWlZwcWlSRlNtclFjR2F2Qi8yWVUzc0FnMDF5Y2t3Y2UzdnZxNU55SkNqcVhVeU11d2t3RTRaTXF3N1ArRDhFNXovUlBmUDZGcElmcVU4TS9XQnI2a1puMUsybTJrczMzcjhsNi9IcmZ5WTFVeDJPMGNKRUxYYTJSNG91d2l3eXhvbzlrZ0wzWGpUMTQyUU5kTDhobW9zOXBtdldNd2VxdFpZRDJTUGRXdXhER1l2Rm51MVRZNlArUnFmdEZhYjczTE5QcXJmODFWL2xMV1hxNzNlSXdTSTJPdmRDaGp6QkppM0E0WVZjU1pMOUZXYXRDT09IYkpDaWNRQlg0bEV5QTVaN2pIUFBXaTZSMTMzc08wZTk5MFBEdmVUeC8zb2NqLzczQTlQOTlQWDVmaDJPUC8vQlFIczhZeVJNVDNkQUFBQUFFbEZUa1N1UW1DQw' 9 | -------------------------------------------------------------------------------- /src/synker.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * synker.js (sync worker) 4 | * The worker for the cloud sync process (spwaned as a child of main process) 5 | * Ensures the sync process runs uninterruptedly (from main) 6 | ******************************/ 7 | const sync = require('./sync') 8 | const logger = require('../script/logger') 9 | const _ = require('lodash') 10 | // const async = require('async') 11 | // const moment = require('moment') 12 | 13 | // Implement with ES6 Generators? 14 | // Spawn a child process for sync worker 15 | // const cp = require('child_process') 16 | // const child = cp.fork('./src/sync_worker') 17 | // 18 | // child.on('put', function (file) { 19 | // // Receive results from child process 20 | // logger.verbose('received: ' + file) 21 | // }) 22 | // 23 | // // Send child process some work 24 | // child.send('Please up-case this string') 25 | 26 | exports.init = function () { 27 | return new Promise(function (resolve, reject) { 28 | // Set drain (callback) handlers 29 | exports.initDrains() 30 | 31 | // Restore queues on startup 32 | if (!_.isEmpty(global.state.toGet)) { 33 | sync.updateStatus('getting') 34 | global.state.toGet.forEach(function (file) { 35 | sync.pushGetQueue(file) 36 | .then((file) => { 37 | return sync.pushCryptQueue(file) 38 | }) 39 | .then((file) => { 40 | return sync.updateStatus('crypted', file) 41 | }) 42 | // .then((file) => { 43 | // return sync.pushUpdateQueue(file) 44 | // }) 45 | // .then(() => { 46 | // return sync.updateStatus('put', file) 47 | // }) 48 | // .then(() => { 49 | // return sync.updateStatus('synced') 50 | // }) 51 | .catch((err) => { 52 | sync.updateStatus('notsynced') 53 | logger.error(`PROMISE ERR: ${err.stack}`) 54 | }) 55 | }) 56 | } 57 | 58 | if (!_.isEmpty(global.state.toCrypt)) { 59 | sync.updateStatus('encrypting') 60 | global.state.toCrypt.forEach(function (file) { 61 | sync.pushCryptQueue(file) 62 | .then((file) => { 63 | return sync.pushUpdateQueue(file) 64 | }) 65 | .then(() => { 66 | return sync.updateStatus('put', file) 67 | }) 68 | .then(() => { 69 | return sync.updateStatus('synced') 70 | }) 71 | .catch((err) => { 72 | sync.updateStatus('notsynced') 73 | logger.error(`PROMISE ERR: ${err.stack}`) 74 | }) 75 | }) 76 | } 77 | 78 | // TODO: 79 | // if (!_.isEmpty(global.state.toUpdate)) { 80 | // sync.updateStatus('putting') 81 | // global.state.toUpdate.forEach(function (file) { 82 | // sync.pushUpdateQueue(file) 83 | // .then(() => { 84 | // return sync.updateStatus('put', file) 85 | // }) 86 | // .then(() => { 87 | // return sync.updateStatus('synced') 88 | // }) 89 | // .catch((err) => { 90 | // sync.updateStatus('notsynced') 91 | // logger.error(`PROMISE ERR: ${err.stack}`) 92 | // }) 93 | // }) 94 | // } 95 | 96 | if (!_.isEmpty(global.state.toPut)) { 97 | sync.updateStatus('putting') 98 | global.state.toPut.forEach(function (file) { 99 | sync.pushPutQueue(file) 100 | .then(() => { 101 | return sync.updateStatus('synced') 102 | }) 103 | .catch((err) => { 104 | sync.updateStatus('notsynced') 105 | logger.error(`PROMISE ERR: ${err.stack}`) 106 | }) 107 | }) 108 | } 109 | resolve() 110 | }) 111 | } 112 | 113 | exports.initDrains = function () { 114 | return new Promise(function (resolve, reject) { 115 | sync.getQueue.drain = function () { 116 | logger.info('DONE getQueue for ALL items') 117 | // start encyrpting 118 | } 119 | 120 | sync.cryptQueue.drain = function () { 121 | logger.info('DONE cryptQueue for ALL items') 122 | // start putting 123 | } 124 | 125 | sync.updateQueue.drain = function () { 126 | logger.info('DONE updateQueue for ALL items') 127 | // start taking off toUpdate 128 | } 129 | resolve() 130 | }) 131 | } 132 | 133 | exports.initWatcher = function () { 134 | 135 | } 136 | -------------------------------------------------------------------------------- /static/js/jquery.marquee.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.marquee - scrolling text like old marquee element 3 | * @author Aamir Afridi - aamirafridi(at)gmail(dot)com / http://aamirafridi.com/jquery/jquery-marquee-plugin 4 | */ 5 | ;(function(d){d.fn.marquee=function(w){return this.each(function(){var a=d.extend({},d.fn.marquee.defaults,w),b=d(this),c,k,p,q,h,l=3,x="animation-play-state",e=!1,B=function(a,b,c){for(var d=["webkit","moz","MS","o",""],e=0;e');var f=b.find(".js-marquee").css({"margin-right":a.gap,"float":"left"});a.duplicated&&f.clone(!0).appendTo(b);b.wrapInner('
');c=b.find(".js-marquee-wrapper"); 8 | if(q){var m=b.height();c.removeAttr("style");b.height(m);b.find(".js-marquee").css({"float":"none","margin-bottom":a.gap,"margin-right":0});a.duplicated&&b.find(".js-marquee:last").css({"margin-bottom":0});var s=b.find(".js-marquee:first").height()+a.gap;a.duration*=(parseInt(s,10)+parseInt(m,10))/parseInt(m,10)}else h=b.find(".js-marquee:first").width()+a.gap,k=b.width(),a.duration*=(parseInt(h,10)+parseInt(k,10))/parseInt(k,10);a.duplicated&&(a.duration/=2);if(a.allowCss3Support){var f=document.body|| 9 | document.createElement("div"),n="marqueeAnimation-"+Math.floor(1E7*Math.random()),z=["Webkit","Moz","O","ms","Khtml"],A="animation",t="",u="";f.style.animation&&(u="@keyframes "+n+" ",e=!0);if(!1===e)for(var y=0;y"+f+"");B(c[0],"AnimationIteration",function(){b.trigger("finished")});B(c[0],"AnimationEnd",function(){v();b.trigger("finished")})}else c.animate(p,a.duration,a.easing,function(){b.trigger("finished");a.pauseOnCycle?b.timer=setTimeout(v,a.delayBeforeStart):v()});b.data("runningStatus","resumed")};b.bind("pause", 13 | g.pause);b.bind("resume",g.resume);a.pauseOnHover&&b.bind("mouseenter mouseleave",g.toggle);e&&a.allowCss3Support?v():b.timer=setTimeout(v,a.delayBeforeStart)}})};d.fn.marquee.defaults={allowCss3Support:!0,css3easing:"linear",easing:"linear",delayBeforeStart:1E3,direction:"left",duplicated:!1,duration:5E3,gap:20,pauseOnCycle:!1,pauseOnHover:!1}})(jQuery); 14 | -------------------------------------------------------------------------------- /static/addaccountprompt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Add a Cloud Service Account 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 | 20 |

Add a Cloud Service Account

21 |
22 |
23 | 30 | 37 |
38 |
39 |
40 |
41 |
42 | 47 |
48 |
49 |
50 | 55 |

Authorising...

56 |
57 |
58 |
59 |
60 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /static/style/mixins.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100vh;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button,.button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,.button:active,button:hover,.button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic} -------------------------------------------------------------------------------- /test/ui/test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const Application = require('spectron').Application 3 | const assert = require('assert') 4 | const chai = require('chai') 5 | const expect = chai.expect 6 | const chaiAsPromised = require('chai-as-promised') 7 | const path = require('path') 8 | const logger = require('../../script/logger') 9 | 10 | chai.should() 11 | chai.use(chaiAsPromised) 12 | 13 | describe("CryptoSync Render Modules's tests", function () { 14 | this.timeout(10000) 15 | 16 | before(function () { 17 | // set vars 18 | }) 19 | 20 | beforeEach(function () { 21 | this.app = new Application({ 22 | // path: '../dest/CryptoSync-darwin-x64/CryptoSync.app/Contents/MacOS/Electron', 23 | path: path.join(__dirname, '../../dest/CryptoSyncTest-darwin-x64/CryptoSyncTest.app/Contents/MacOS/CryptoSyncTest') 24 | }) 25 | return this.app.start() 26 | }) 27 | 28 | afterEach(function () { 29 | if (this.app && this.app.isRunning()) { 30 | return this.app.stop() 31 | } 32 | }) 33 | 34 | it('should show setup window', function () { 35 | return this.app.client.getWindowCount().then(function (count) { 36 | assert.equal(count, 1) 37 | }) 38 | }) 39 | 40 | describe('Setup', function () { 41 | before(() => { 42 | }) 43 | 44 | it('should give response for incorrect masterpass', function () { 45 | return this.app.client 46 | .getHTML('body', function (err, html) { 47 | logger.info(html) 48 | logger.info(err) 49 | }) 50 | }) 51 | 52 | // it('should give response for empty masterpass', function () { 53 | // const masterpass = '' 54 | // return this.app.client 55 | // .setValue('#checkMasterPassInput', masterpass) 56 | // .click('#checkMasterPass') 57 | // .then(() => { 58 | // return new Promise(function (resolve, reject) { 59 | // setTimeout(function () { 60 | // resolve() 61 | // }, 200) 62 | // }) 63 | // }) 64 | // .getText('#checkMasterPassLabel') 65 | // .should.eventually.equal(responses.empty) 66 | // }) 67 | }) 68 | 69 | // describe('Main', function () { 70 | // var responses 71 | // before(() => { 72 | // responses = { 73 | // invalid: 'INVALID MASTERPASS', 74 | // incorrect: 'INCORRECT MASTERPASS', 75 | // correct: 'CORRECT MASTERPASS', 76 | // setSuccess: 'MASTERPASS SUCCESSFULLY SET', 77 | // empty: 'PLEASE ENTER A MASTERPASS', 78 | // } 79 | // }) 80 | // 81 | // 82 | // it('should give response for incorrect masterpass', function () { 83 | // const masterpass = 'yolo#10111' 84 | // return this.app.client 85 | // .setValue('#checkMasterPassInput', masterpass) 86 | // .click('#checkMasterPass') 87 | // .then(() => { 88 | // return new Promise(function (resolve, reject) { 89 | // setTimeout(function () { 90 | // resolve() 91 | // }, 200) 92 | // }) 93 | // }) 94 | // .getText('#checkMasterPassLabel') 95 | // .should.eventually.equal(responses.incorrect) 96 | // }) 97 | // 98 | // it('should give response for invalid masterpass', function () { 99 | // const masterpass = 'yolo#10' 100 | // return this.app.client 101 | // .setValue('#checkMasterPassInput', masterpass) 102 | // .click('#checkMasterPass') 103 | // .then(() => { 104 | // return new Promise(function (resolve, reject) { 105 | // setTimeout(function () { 106 | // resolve() 107 | // }, 200) 108 | // }) 109 | // }) 110 | // .getText('#checkMasterPassLabel') 111 | // .should.eventually.equal(responses.invalid) 112 | // }) 113 | // 114 | // it('should give response for empty masterpass', function () { 115 | // const masterpass = '' 116 | // return this.app.client 117 | // .setValue('#checkMasterPassInput', masterpass) 118 | // .click('#checkMasterPass') 119 | // .then(() => { 120 | // return new Promise(function (resolve, reject) { 121 | // setTimeout(function () { 122 | // resolve() 123 | // }, 200) 124 | // }) 125 | // }) 126 | // .getText('#checkMasterPassLabel') 127 | // .should.eventually.equal(responses.empty) 128 | // }) 129 | // 130 | // it('should give response for correct masterpass', function () { 131 | // const masterpass = 'yolo#101' 132 | // return this.app.client 133 | // .setValue('#checkMasterPassInput', masterpass) 134 | // .click('#checkMasterPass') 135 | // .then(() => { 136 | // return new Promise(function (resolve, reject) { 137 | // setTimeout(function () { 138 | // resolve() 139 | // }, 200) 140 | // }) 141 | // }) 142 | // .getText('#checkMasterPassLabel') 143 | // .should.eventually.equal(responses.correct) 144 | // }) 145 | // }) 146 | }) 147 | -------------------------------------------------------------------------------- /static/style/errorprompt.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100%;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic}.container{display:flex;align-items:center;justify-content:center}#errorprompt{margin-top:2rem;max-width:85%}button{width:40%;font-size:.8rem}h1{font-size:.8rem;font-weight:300} -------------------------------------------------------------------------------- /static/style/menubar.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100vh;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button,.button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,.button:active,button:hover,.button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic}@keyframes spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}section#menubar{min-height:100%;position:relative;background-color:#FFFFFF;overflow:hidden}header{clear:both;padding:.4rem 0 .4rem .8rem;margin:0;font-size:.8rem;border-top:1px solid #DDDDDD;border-bottom:1px solid #DDDDDD}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}div.fileList{height:12.6rem;width:100%;overflow-y:auto;margin-bottom:2.4rem}.spin{width:1.2rem;z-index:0;-webkit-animation:spin 4s linear infinite;animation:spin 4s linear infinite}div.content,div.type{display:inline-block;position:relative}div.content{width:80%;vertical-align:top;margin-left:.4rem}div.name{font-size:.8rem;text-overflow:ellipsis;position:relative;overflow:hidden;width:95%}div.lastSynced{font-size:.6rem}div.cloudType{position:absolute;bottom:-1px;right:-4px}div.cloudType>img{height:.8rem;width:auto;opacity:1}img.fileType{width:1.4rem;padding-left:.8rem;margin:0}div.item{width:100%;border-top:1px solid #DDDDDD;padding:.4rem 0}div.status{display:flex;display:-webkit-flex;align-items:center;left:0;bottom:0}div.status>span{font-size:.9rem}div.head{display:flex;display:-webkit-flex;align-items:center}div.status>img{margin-right:.4rem !important}footer{display:flex;clear:both;position:absolute;border-top:1px solid #DDDDDD;width:100%;padding-bottom:0;background-color:#FFFFFF;bottom:0;left:0}img.icon{height:1.2rem;display:inline;margin:.6rem .8rem}div.item:first-child{border-top:none !important} -------------------------------------------------------------------------------- /static/style/vault.less: -------------------------------------------------------------------------------- 1 | // out: ./vault.css, compress: true 2 | /* Menubar styles 3 | 4 | TODO: 5 | - FIX header 6 | - USE 7 | width: @var; 8 | white-space: nowrap; 9 | overflow: hidden; 10 | text-overflow: ellipsis; 11 | to add "..." to overflow text 12 | 13 | - USE flex for footer throughout 14 | 15 | ========================================================================== 16 | */ 17 | @import (less) "mixins.less"; 18 | @lighter: #fefefe; 19 | /*@light * 1.1111*/ 20 | @accounts-txt-width: 5rem; 21 | @border-width: 2px; 22 | @side-margin: 0.8rem; 23 | @name-fsize: 1rem; 24 | @header-fsize: 1rem; 25 | @spacing04: 0.4rem; 26 | @spacing08: 0.8rem; 27 | @spacing-ic-txt: @side-margin - 0.4rem; 28 | @lastMod-fsize: 0.8rem; 29 | @ic-size: 1.4rem; 30 | @profile-size: 1.8rem; 31 | @name-fsize: 0.8rem; 32 | @win-height: 100%; 33 | h3 { 34 | margin: 0.5rem 0; 35 | font-weight: normal; 36 | } 37 | p { 38 | margin: 0; 39 | } 40 | input[type=text] { 41 | border: none; 42 | border-bottom: 1px solid @light; 43 | outline: none; 44 | vertical-align: top; 45 | &:focus { 46 | animation-name: colorTrans; 47 | animation-duration: 2s; 48 | border-bottom: 1px solid @black; 49 | } 50 | } 51 | section#vault { 52 | display: flex; 53 | flex-direction: column; 54 | position: relative; 55 | overflow: hidden; 56 | } 57 | .left { 58 | -webkit-align-self: flex-start; 59 | align-self: flex-start; 60 | } 61 | .right { 62 | margin-left: auto; 63 | } 64 | div.main { 65 | width: 100% !important; 66 | display: flex; 67 | margin: auto; 68 | } 69 | .centre { 70 | width: 100% !important; 71 | margin: auto; 72 | position: absolute; 73 | } 74 | header.top { 75 | display: flex; 76 | position: relative; 77 | height: 2.4rem; 78 | width: 100%; 79 | border-bottom: 1px solid @light; 80 | a > img.icon { 81 | padding-left: 0.5rem; 82 | } 83 | img.icon { 84 | padding: 0.5rem; 85 | } 86 | button { 87 | height: 2rem; 88 | width: 2rem; 89 | background-size: 1.2rem !important; 90 | } 91 | } 92 | div.segment { 93 | flex: 1; 94 | border-left: 1px solid @light; 95 | } 96 | div.row:last-child { 97 | border-bottom: none !important; 98 | } 99 | div.row:only-child { 100 | border: none !important; 101 | } 102 | div.row { 103 | display: block; 104 | } 105 | div#accounts { 106 | height: 100vh; 107 | flex: 1; 108 | width: 100%; 109 | .selected { 110 | border-left: 2px solid @orange_d; 111 | } 112 | .row { 113 | width: inherit; 114 | align-items: center; 115 | border-bottom: 1px solid @light; 116 | padding: @spacing04 0 @spacing04 @spacing04; 117 | text-align: left; 118 | } 119 | .content { 120 | width: 90%; 121 | position: relative; 122 | vertical-align: 100%; 123 | } 124 | 125 | .type { 126 | width: @profile-size * 1.2; 127 | position: relative; 128 | float: left; 129 | } 130 | .content, 131 | .type { 132 | 133 | } 134 | 135 | .name { 136 | font-weight: normal; 137 | font-size: @name-fsize; 138 | white-space: nowrap; 139 | overflow: hidden; 140 | text-overflow: ellipsis; 141 | } 142 | .email { 143 | font-size: @name-fsize - 0.2rem; 144 | white-space: nowrap; 145 | overflow: hidden; 146 | text-overflow: ellipsis; 147 | } 148 | .cloudType { 149 | position: absolute; 150 | bottom: -(@profile-size * 0.1); 151 | left: (@profile-size * 0.6); 152 | } 153 | .cloudType > img { 154 | height: @profile-size * 0.4; 155 | width: auto; 156 | } 157 | .profile { 158 | width: @profile-size; 159 | height: @profile-size; 160 | margin: 0; 161 | border-radius: 50%; 162 | background-position: center center !important; 163 | background-size: @profile-size @profile-size !important; 164 | } 165 | } 166 | div#files { 167 | height: 100vh; 168 | flex: 1.2; 169 | width: 100%; 170 | header { 171 | padding: 0.2rem 0 0.2rem 0.8rem; 172 | background-color: @light; 173 | h4 { 174 | margin: 0; 175 | font-size: 0.8rem; 176 | font-weight: normal; 177 | } 178 | } 179 | div.table { 180 | width: 100%; 181 | max-height: @win-height; 182 | overflow-y: auto; 183 | } 184 | .selected { 185 | border-left: 2px solid @orange_d; 186 | } 187 | .row { 188 | flex-direction: column; 189 | border-bottom: 1px solid @light; 190 | padding: @spacing04 @spacing04 @spacing04 @spacing08; 191 | text-align: left; 192 | } 193 | .name { 194 | font-weight: normal; 195 | font-size: 0.8rem; 196 | } 197 | .lastMod { 198 | font-size: 0.6rem; 199 | } 200 | input[type=text] { 201 | width: 90%; 202 | margin: 0.5rem; 203 | font-size: 0.8rem; 204 | background: url('../images/icons/search.svg') left center no-repeat; 205 | background-size: 0.8rem; 206 | 207 | &:focus { 208 | background: none; 209 | } 210 | &:focus::-webkit-input-placeholder::before { 211 | content: 'Search files\A'; 212 | } 213 | } 214 | } 215 | div#info { 216 | height: 90vh; 217 | flex: 1.8; 218 | display: flex; 219 | flex-direction: column; 220 | background-color: @lighter; 221 | #content { 222 | flex: 1; 223 | margin: 1rem; 224 | table { 225 | font-size: 0.7rem; 226 | tr { 227 | margin-top: 0.4rem; 228 | display: inline-block; 229 | .bttline { 230 | vertical-align: inherit; 231 | } 232 | td { 233 | vertical-align: top; 234 | input[type="text"] { 235 | width: 80%; 236 | } 237 | a > img { 238 | height: 1rem; 239 | margin-left: 0.1rem; 240 | } 241 | } 242 | td:first-child { 243 | text-align: right; 244 | color: @dark * 0.8; 245 | } 246 | td:last-child { 247 | text-align: left; 248 | padding-left: 0.2rem; 249 | } 250 | } 251 | } 252 | } 253 | } 254 | img.icon { 255 | width: auto; 256 | height: @ic-size; 257 | } 258 | footer { 259 | display: flex; 260 | border-top: 1px solid @light; 261 | width: 100%; 262 | button { 263 | height: 1rem; 264 | margin: 0.2rem 0.8rem 0.2rem 0; 265 | } 266 | a > img { 267 | height: 1rem; 268 | margin: 0.2rem 0.4rem 0.2rem 0rem; 269 | } 270 | } 271 | @keyframes colorTrans { 272 | from { 273 | border-bottom: 1px solid @light; 274 | } 275 | to { 276 | border-bottom: 1px solid @black; 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /static/menubar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Crypto.Sync 7 | 8 | 9 | 10 | 11 | 32 | 48 | 52 | 53 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /static/style/masterpassprompt.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100%;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic}header{margin:0}header>p{color:#222222}h1{font-size:1.4rem;margin-bottom:.1rem}p{margin:0}a{font-size:.8rem;color:#222222;text-decoration:none;outline:none}#masterpassprompt{height:100%;min-height:20rem;width:100%;background-color:#FFFFFF;text-align:center;overflow:hidden}#vault{width:7rem;height:auto;margin:2rem auto 0}.panel-container{position:relative}.panel-container>div{display:block;position:absolute;text-align:center;padding:0 3rem 3rem;transform:translateX(-100%);transition:transform .3s}.panel-container>div.current~div{transform:translateX(100%)}.panel-container>div.current{transform:none;position:relative}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;padding:0 .5rem;transition:max-height .3s,padding .3s;background-color:#efefef;font-size:.8rem}img.info{float:right;height:.9rem}img.info:hover+p.info{max-height:10rem;padding-top:.5rem;padding-bottom:.5rem}div.masterpass>input{width:98%}input[type=password]{margin-top:1rem;border:none;border-bottom:1px solid #DDDDDD;outline:none}input[type=password]:focus{animation-name:colorTrans;animation-duration:2s;border-bottom:1px solid #333333}.invalid{border-color:#9F3A38 !important}a.back{float:left}a.back>img{height:1rem;width:auto}div.forgotMP{padding:.2rem .2rem 0 0;text-align:right}input[type=submit]{margin-top:1rem;height:2rem;font-weight:normal;background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;outline:none}input[type=submit]:active,input[type=submit]:hover{background-color:#DDDDDD}div.submit{text-align:right;background-color:#FFFFFF;width:100%}footer{display:flex;clear:both;position:absolute;border-top:1px solid #DDDDDD;width:100%;padding-bottom:0;background-color:#FFFFFF;bottom:0;left:0}footer>a{float:right;padding:.2rem}a.back{float:left}a.back>img{height:1rem;width:auto}div.masterpass>label{display:inline-block;font-size:.8rem;margin:.2rem 0;color:#9F3A38} -------------------------------------------------------------------------------- /static/style/settings.less: -------------------------------------------------------------------------------- 1 | // out: ./settings.css, compress: true 2 | /* Settings styles 3 | ========================================================================== 4 | */ 5 | @import (less) "mixins.less"; 6 | /* Variable declarations*/ 7 | @list-height: 10rem; 8 | @border-width: 2px; 9 | @side-margin: 0.8rem; 10 | @name-fsize: 1rem; 11 | @header-fsize: 1rem; 12 | @spacing04: 0.4rem; 13 | @spacing-ic-txt: @side-margin - 0.4rem; 14 | @email-fsize: 0.8rem; 15 | @profile-size: 4rem; 16 | @ic-size: 1.4rem; 17 | .panel-container { 18 | overflow: hidden; 19 | position: relative; 20 | & > div:not(.menu) { 21 | position : absolute; 22 | text-align: center; 23 | transform : translateX(-110%); 24 | transition: transform 0.5s; 25 | & > button { 26 | margin-top: 1rem; 27 | } 28 | } 29 | & > div.current { 30 | width : 100%; 31 | height : 100%; 32 | transform: none; 33 | position : relative; 34 | } 35 | & > div.current ~ div { 36 | transform: translateX(110%); 37 | } 38 | header { 39 | margin-top: 2rem; 40 | } 41 | } 42 | section#settings { 43 | min-height : 100%; 44 | position : relative; 45 | background-color: @white; 46 | } 47 | a:not(.navigationLink) { 48 | font-size : 0.8rem; 49 | color : @blacker; 50 | text-decoration: none; 51 | outline : none; 52 | } 53 | a.navigationLink { 54 | font-size: 0.9rem; 55 | } 56 | .left { 57 | -webkit-align-self: flex-start; 58 | align-self : flex-start; 59 | } 60 | .right { 61 | margin-left: auto; 62 | } 63 | .menu { 64 | display : flex; 65 | margin-left : 0; 66 | margin-right : 0; 67 | border-bottom: @border-width solid rgba(0, 0, 0, 0.15); 68 | align-self : flex-end; 69 | transition : color 0.1s ease; 70 | } 71 | .menu:after { 72 | content : ''; 73 | display : block; 74 | height : 0; 75 | clear : both; 76 | visibility: hidden; 77 | } 78 | .menu .item:after { 79 | display: none; 80 | } 81 | .menu .item { 82 | position : relative; 83 | cursor : pointer; 84 | line-height : 1.4rem; 85 | text-decoration : none; 86 | -webkit-tap-highlight-color: transparent; 87 | -webkit-box-flex : 0; 88 | flex : 0 0 auto; 89 | -webkit-user-select : none; 90 | user-select : none; 91 | padding : 0.6rem 1.15rem; 92 | padding-top: 1rem; 93 | text-transform : none; 94 | color : rgba(0, 0, 0, 0.87); 95 | transition : background 0.1s ease, box-shadow 0.1s ease, color 0.1s ease; 96 | } 97 | a.item:active { 98 | border-bottom: @border-width solid rgba(0, 0, 0, 0.1); 99 | margin-bottom: -@border-width; 100 | } 101 | .active.item { 102 | background-color: transparent; 103 | box-shadow : none; 104 | border-color : @black; 105 | font-weight : 700; 106 | margin-bottom : -@border-width; 107 | color : rgba(0,0,0,.95); 108 | } 109 | .menu .active.item { 110 | border-bottom: @border-width solid rgba(0, 0, 0, 0.8); 111 | color : rgba(0, 0, 0, 0.95); 112 | font-weight : normal; 113 | box-shadow : none; 114 | } 115 | .item.right { 116 | display : flex; 117 | margin-left: auto !important; 118 | } 119 | img.icon { 120 | width : @ic-size; 121 | height: @ic-size; 122 | } 123 | h3 { 124 | margin : 0.5rem 0; 125 | font-weight: normal; 126 | } 127 | h4 { 128 | margin-top : 0.5rem; 129 | margin-bottom: 0.5rem; 130 | font-weight : 300; 131 | text-align : left; 132 | border-bottom: 1px solid @light; 133 | } 134 | section.category { 135 | text-align: left; 136 | } 137 | div.options { 138 | margin-left: 1rem; 139 | } 140 | div.option { 141 | display : flex; 142 | margin-top: 0.2rem; 143 | font-size : 0.8rem; 144 | } 145 | span.config.right { 146 | color: @darker 147 | } 148 | div.list { 149 | height : @list-height; 150 | width : 100%; 151 | overflow-y: auto; 152 | } 153 | button.add { 154 | margin-bottom: 2rem; 155 | } 156 | div.item { 157 | display : flex; 158 | align-items : center; 159 | border-bottom: 1px solid @light; 160 | padding : @spacing04 0; 161 | text-align : left; 162 | } 163 | div.content, 164 | div.type { 165 | display : inline-block; 166 | position: relative; 167 | } 168 | div.content { 169 | vertical-align: 100%; 170 | margin-left : @spacing-ic-txt; 171 | } 172 | div.name { 173 | font-weight: 400; 174 | } 175 | div.email { 176 | font-size: @email-fsize; 177 | } 178 | div.qouta { 179 | font-size : 0.6rem; 180 | margin-top: 0.1rem; 181 | color: @darker; 182 | } 183 | div.cloudType { 184 | position: absolute; 185 | bottom : 2px; 186 | right : 2px; 187 | } 188 | div.cloudType > img { 189 | height: 1rem; 190 | width : auto; 191 | } 192 | div.profile { 193 | width : @profile-size; 194 | height : @profile-size; 195 | margin : 0; 196 | border-radius : 50%; 197 | background-position: center center !important; 198 | background-size : @profile-size @profile-size !important; 199 | } 200 | section.contribute { 201 | footer { 202 | padding-bottom : 1rem; 203 | text-align : center; 204 | display : flex; 205 | align-items : center; 206 | font-size : 0.8rem; 207 | justify-content: center; 208 | img { 209 | height: 1rem !important; 210 | } 211 | } 212 | div.list { 213 | width : 100%; 214 | margin-bottom: 3rem; 215 | height : 100%; 216 | .item { 217 | a { 218 | cursor : pointer; 219 | display : flex; 220 | align-items: center; 221 | text-align : left; 222 | } 223 | .name { 224 | font-weight: 300; 225 | } 226 | .icon { 227 | padding: 0.4rem; 228 | } 229 | } 230 | } 231 | } 232 | section.contribute { 233 | width: 70%; 234 | margin: auto; 235 | margin-top: 1rem; 236 | header { 237 | border-bottom: 1px solid @light; 238 | img { 239 | height: 4rem !important; 240 | width : auto; 241 | } 242 | } 243 | } 244 | section.accounts { 245 | width: 70%; 246 | margin: auto; 247 | margin-top: 1rem; 248 | header { 249 | border-bottom: 1px solid @light; 250 | img { 251 | height: 4rem !important; 252 | width : auto; 253 | } 254 | } 255 | } 256 | section.crypto { 257 | width : 90%; 258 | margin: auto; 259 | margin-top : 1rem; 260 | margin-bottom: 1rem; 261 | header > img { 262 | height: 4rem !important; 263 | width : auto; 264 | } 265 | button { 266 | width: 20%; 267 | } 268 | } 269 | section.sync { 270 | width : 90%; 271 | margin: auto; 272 | margin-top : 1rem; 273 | margin-bottom: 1rem; 274 | header > img { 275 | height: 4rem !important; 276 | width : auto; 277 | } 278 | button { 279 | width: 20%; 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /static/style/mixins.less: -------------------------------------------------------------------------------- 1 | // out: ./mixins.css, compress: true 2 | @import (css) "../../bower_components/normalize-css/normalize.css"; 3 | 4 | /* theme colors */ 5 | @white: #FFFFFF; 6 | @light: #DDDDDD; 7 | @dark: #9D9D9D; 8 | @darker: #555555; 9 | @black: #333333; 10 | @blacker: #222222; 11 | @invalid-color: #F05A5C; 12 | @orange: #EEA849; 13 | @orange_d: #F46B45; 14 | 15 | /* Animations */ 16 | @keyframes colorTrans { 17 | from { 18 | border-bottom: 1px solid @light; 19 | } 20 | to { 21 | border-bottom: 1px solid @black; 22 | } 23 | } 24 | 25 | /* General (shared) styles */ 26 | body { 27 | font-family : "Roboto", "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, "Lucida Grande", sans-serif; 28 | font-weight : 300; 29 | margin : 0; 30 | padding : 0; 31 | background-color: @white; 32 | width : 100%; 33 | height : 100vh; 34 | overflow : hidden; 35 | } 36 | p { 37 | margin: 0; 38 | } 39 | div.none { 40 | display: none; 41 | } 42 | .left { 43 | -webkit-align-self: flex-start; 44 | align-self : flex-start !important; 45 | } 46 | .right { 47 | margin-left: auto !important; 48 | } 49 | button, .button { 50 | background-color: @white; 51 | border : 1px solid @light; 52 | width : 100%; 53 | padding : 0.3rem; 54 | font-weight : 400; 55 | outline : none; 56 | &:active, 57 | &:hover { 58 | background-color: @light; 59 | } 60 | } 61 | button.fancy { 62 | margin-top : 0.2rem; 63 | border : none; 64 | color : @white; 65 | width : 30% !important; 66 | background : linear-gradient(to right, @orange, @orange_d); 67 | background-size: 200% 200%; 68 | animation : OrangeAnimGrad 3s ease infinite; 69 | &:active, 70 | &:hover { 71 | opacity: 0.8; 72 | } 73 | } 74 | img.info { 75 | padding-left: 0.2rem; 76 | height : 0.8rem; 77 | } 78 | p.info { 79 | display : block; 80 | width : 100%; 81 | box-sizing : border-box; 82 | max-height : 0; 83 | overflow : hidden; 84 | transition : max-height 0.5s, padding 0.3s; 85 | background-color: @light; 86 | font-size : 0.8rem; 87 | } 88 | img.info:hover + p.info { 89 | max-height: 100%; 90 | padding : 0.2rem; 91 | } 92 | 93 | /* Page transitions */ 94 | .moveUp-enter { 95 | transition-duration : 0.3s; 96 | transition-property : transform, opacity; 97 | transition-timing-function: ease-out; 98 | transform : translate3d(0,100%,0); 99 | z-index : 10000; 100 | } 101 | .moveUp-enter.moveUp-enter-active { 102 | transform: translate3d(0,0,0); 103 | } 104 | .moveUp-leave { 105 | transition-duration : 0.3s; 106 | transition-property : transform, opacity; 107 | transition-timing-function: ease-out; 108 | transform : translate3d(0,0,0); 109 | opacity : 1; 110 | } 111 | .moveUp-leave.moveUp-leave-active { 112 | transform: translate3d(0,-15%,0); 113 | opacity : 0.3; 114 | } 115 | 116 | /* font declarations */ 117 | @font-face { 118 | font-family: 'Roboto'; 119 | src : url('../fonts/Roboto-Italic.eot'); 120 | src : url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Italic.woff') format('woff'), url('../fonts/Roboto-Italic.ttf') format('truetype'); 121 | font-weight: normal; 122 | font-style : italic; 123 | } 124 | @font-face { 125 | font-family: 'Roboto'; 126 | src : url('../fonts/Roboto-BlackItalic.eot'); 127 | src : url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-BlackItalic.woff') format('woff'), url('../fonts/Roboto-BlackItalic.ttf') format('truetype'); 128 | font-weight: 900; 129 | font-style : italic; 130 | } 131 | @font-face { 132 | font-family: 'Roboto'; 133 | src : url('../fonts/Roboto-Bold.eot'); 134 | src : url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Bold.woff') format('woff'), url('../fonts/Roboto-Bold.ttf') format('truetype'); 135 | font-weight: bold; 136 | font-style : normal; 137 | } 138 | @font-face { 139 | font-family: 'Roboto'; 140 | src : url('../fonts/Roboto-Thin.eot'); 141 | src : url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Thin.woff') format('woff'), url('../fonts/Roboto-Thin.ttf') format('truetype'); 142 | font-weight: 100; 143 | font-style : normal; 144 | } 145 | @font-face { 146 | font-family: 'Roboto'; 147 | src : url('../fonts/Roboto-Medium.eot'); 148 | src : url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Medium.woff') format('woff'), url('../fonts/Roboto-Medium.ttf') format('truetype'); 149 | font-weight: 500; 150 | font-style : normal; 151 | } 152 | @font-face { 153 | font-family: 'Roboto'; 154 | src : url('../fonts/Roboto-Light.eot'); 155 | src : url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Light.woff') format('woff'), url('../fonts/Roboto-Light.ttf') format('truetype'); 156 | font-weight: 300; 157 | font-style : normal; 158 | } 159 | @font-face { 160 | font-family: 'Roboto'; 161 | src : url('../fonts/Roboto-Regular.eot'); 162 | src : url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Regular.woff') format('woff'), url('../fonts/Roboto-Regular.ttf') format('truetype'); 163 | font-weight: normal; 164 | font-style : normal; 165 | } 166 | @font-face { 167 | font-family: 'Roboto'; 168 | src : url('../fonts/Roboto-ThinItalic.eot'); 169 | src : url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-ThinItalic.woff') format('woff'), url('../fonts/Roboto-ThinItalic.ttf') format('truetype'); 170 | font-weight: 100; 171 | font-style : italic; 172 | } 173 | @font-face { 174 | font-family: 'Roboto'; 175 | src : url('../fonts/Roboto-BoldItalic.eot'); 176 | src : url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-BoldItalic.woff') format('woff'), url('../fonts/Roboto-BoldItalic.ttf') format('truetype'); 177 | font-weight: bold; 178 | font-style : italic; 179 | } 180 | @font-face { 181 | font-family: 'Roboto'; 182 | src : url('../fonts/Roboto-Black.eot'); 183 | src : url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-Black.woff') format('woff'), url('../fonts/Roboto-Black.ttf') format('truetype'); 184 | font-weight: 900; 185 | font-style : normal; 186 | } 187 | @font-face { 188 | font-family: 'Roboto'; 189 | src : url('../fonts/Roboto-MediumItalic.eot'); 190 | src : url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-MediumItalic.woff') format('woff'), url('../fonts/Roboto-MediumItalic.ttf') format('truetype'); 191 | font-weight: 500; 192 | font-style : italic; 193 | } 194 | @font-face { 195 | font-family: 'Roboto'; 196 | src : url('../fonts/Roboto-LightItalic.eot'); 197 | src : url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'), url('../fonts/Roboto-LightItalic.woff') format('woff'), url('../fonts/Roboto-LightItalic.ttf') format('truetype'); 198 | font-weight: 300; 199 | font-style : italic; 200 | } 201 | -------------------------------------------------------------------------------- /static/style/vault.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100vh;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button,.button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,.button:active,button:hover,.button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic}h3{margin:.5rem 0;font-weight:normal}p{margin:0}input[type=text]{border:none;border-bottom:1px solid #DDDDDD;outline:none;vertical-align:top}input[type=text]:focus{animation-name:colorTrans;animation-duration:2s;border-bottom:1px solid #333333}section#vault{display:flex;flex-direction:column;position:relative;overflow:hidden}.left{-webkit-align-self:flex-start;align-self:flex-start}.right{margin-left:auto}div.main{width:100% !important;display:flex;margin:auto}.centre{width:100% !important;margin:auto;position:absolute}header.top{display:flex;position:relative;height:2.4rem;width:100%;border-bottom:1px solid #DDDDDD}header.top a>img.icon{padding-left:.5rem}header.top img.icon{padding:.5rem}header.top button{height:2rem;width:2rem;background-size:1.2rem !important}div.segment{flex:1;border-left:1px solid #DDDDDD}div.row:last-child{border-bottom:none !important}div.row:only-child{border:none !important}div.row{display:block}div#accounts{height:100vh;flex:1;width:100%}div#accounts .selected{border-left:2px solid #F46B45}div#accounts .row{width:inherit;align-items:center;border-bottom:1px solid #DDDDDD;padding:.4rem 0 .4rem .4rem;text-align:left}div#accounts .content{width:90%;position:relative;vertical-align:100%}div#accounts .type{width:2.16rem;position:relative;float:left}div#accounts .name{font-weight:normal;font-size:.8rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}div#accounts .email{font-size:.6rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}div#accounts .cloudType{position:absolute;bottom:-0.18rem;left:1.08rem}div#accounts .cloudType>img{height:.72rem;width:auto}div#accounts .profile{width:1.8rem;height:1.8rem;margin:0;border-radius:50%;background-position:center center !important;background-size:1.8rem 1.8rem !important}div#files{height:100vh;flex:1.2;width:100%}div#files header{padding:.2rem 0 .2rem .8rem;background-color:#DDDDDD}div#files header h4{margin:0;font-size:.8rem;font-weight:normal}div#files div.table{width:100%;max-height:100%;overflow-y:auto}div#files .selected{border-left:2px solid #F46B45}div#files .row{flex-direction:column;border-bottom:1px solid #DDDDDD;padding:.4rem .4rem .4rem .8rem;text-align:left}div#files .name{font-weight:normal;font-size:.8rem}div#files .lastMod{font-size:.6rem}div#files input[type=text]{width:90%;margin:.5rem;font-size:.8rem;background:url('../images/icons/search.svg') left center no-repeat;background-size:.8rem}div#files input[type=text]:focus{background:none}div#files input[type=text]:focus::-webkit-input-placeholder::before{content:'Search files\A'}div#info{height:90vh;flex:1.8;display:flex;flex-direction:column;background-color:#fefefe}div#info #content{flex:1;margin:1rem}div#info #content table{font-size:.7rem}div#info #content table tr{margin-top:.4rem;display:inline-block}div#info #content table tr .bttline{vertical-align:inherit}div#info #content table tr td{vertical-align:top}div#info #content table tr td input[type="text"]{width:80%}div#info #content table tr td a>img{height:1rem;margin-left:.1rem}div#info #content table tr td:first-child{text-align:right;color:#7e7e7e}div#info #content table tr td:last-child{text-align:left;padding-left:.2rem}img.icon{width:auto;height:1.4rem}footer{display:flex;border-top:1px solid #DDDDDD;width:100%}footer button{height:1rem;margin:.2rem .8rem .2rem 0}footer a>img{height:1rem;margin:.2rem .4rem .2rem 0}@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}} -------------------------------------------------------------------------------- /static/style/settings.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100vh;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic}.panel-container{overflow:hidden;position:relative}.panel-container>div:not(.menu){position:absolute;text-align:center;transform:translateX(-110%);transition:transform .5s}.panel-container>div:not(.menu)>button{margin-top:1rem}.panel-container>div.current{width:100%;height:100%;transform:none;position:relative}.panel-container>div.current~div{transform:translateX(110%)}.panel-container header{margin-top:2rem}section#settings{min-height:100%;position:relative;background-color:#FFFFFF}a:not(.navigationLink){font-size:.8rem;color:#222222;text-decoration:none;outline:none}a.navigationLink{font-size:.9rem}.left{-webkit-align-self:flex-start;align-self:flex-start}.right{margin-left:auto}.menu{display:flex;margin-left:0;margin-right:0;border-bottom:2px solid rgba(0,0,0,0.15);align-self:flex-end;transition:color .1s ease}.menu:after{content:'';display:block;height:0;clear:both;visibility:hidden}.menu .item:after{display:none}.menu .item{position:relative;cursor:pointer;line-height:1.4rem;text-decoration:none;-webkit-tap-highlight-color:transparent;-webkit-box-flex:0;flex:0 0 auto;-webkit-user-select:none;user-select:none;padding:.6rem 1.15rem;padding-top:1rem;text-transform:none;color:rgba(0,0,0,0.87);transition:background .1s ease,box-shadow .1s ease,color .1s ease}a.item:active{border-bottom:2px solid rgba(0,0,0,0.1);margin-bottom:-2px}.active.item{background-color:transparent;box-shadow:none;border-color:#333333;font-weight:700;margin-bottom:-2px;color:rgba(0,0,0,0.95)}.menu .active.item{border-bottom:2px solid rgba(0,0,0,0.8);color:rgba(0,0,0,0.95);font-weight:normal;box-shadow:none}.item.right{display:flex;margin-left:auto !important}img.icon{width:1.4rem;height:1.4rem}h3{margin:.5rem 0;font-weight:normal}h4{margin-top:.5rem;margin-bottom:.5rem;font-weight:300;text-align:left;border-bottom:1px solid #DDDDDD}section.category{text-align:left}div.options{margin-left:1rem}div.option{display:flex;margin-top:.2rem;font-size:.8rem}span.config.right{color:#555555}div.list{height:10rem;width:100%;overflow-y:auto}button.add{margin-bottom:2rem}div.item{display:flex;align-items:center;border-bottom:1px solid #DDDDDD;padding:.4rem 0;text-align:left}div.content,div.type{display:inline-block;position:relative}div.content{vertical-align:100%;margin-left:.4rem}div.name{font-weight:400}div.email{font-size:.8rem}div.qouta{font-size:.6rem;margin-top:.1rem;color:#555555}div.cloudType{position:absolute;bottom:2px;right:2px}div.cloudType>img{height:1rem;width:auto}div.profile{width:4rem;height:4rem;margin:0;border-radius:50%;background-position:center center !important;background-size:4rem 4rem !important}section.contribute footer{padding-bottom:1rem;text-align:center;display:flex;align-items:center;font-size:.8rem;justify-content:center}section.contribute footer img{height:1rem !important}section.contribute div.list{width:100%;margin-bottom:3rem;height:100%}section.contribute div.list .item a{cursor:pointer;display:flex;align-items:center;text-align:left}section.contribute div.list .item .name{font-weight:300}section.contribute div.list .item .icon{padding:.4rem}section.contribute{width:70%;margin:auto;margin-top:1rem}section.contribute header{border-bottom:1px solid #DDDDDD}section.contribute header img{height:4rem !important;width:auto}section.accounts{width:70%;margin:auto;margin-top:1rem}section.accounts header{border-bottom:1px solid #DDDDDD}section.accounts header img{height:4rem !important;width:auto}section.crypto{width:90%;margin:auto;margin-top:1rem;margin-bottom:1rem}section.crypto header>img{height:4rem !important;width:auto}section.crypto button{width:20%}section.sync{width:90%;margin:auto;margin-top:1rem;margin-bottom:1rem}section.sync header>img{height:4rem !important;width:auto}section.sync button{width:20%} -------------------------------------------------------------------------------- /static/masterpassprompt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unlock the Vault 6 | 7 | 8 | 9 | 10 | 11 |
12 | some 13 |
14 |
15 |
16 |

Unlock the Vault

17 |

Please enter your Master Password to unlock the vault 18 |

19 | 20 |

The Vault that contains all the secret keys for your encrypted data is encrypted using a Master Password - your MasterPass

21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 | Forgot MasterPass? 29 |
30 |
31 | 32 |
33 |
34 | 37 |
38 | 61 |
62 |
63 |

Reset the MasterPass

64 |

Please enter a new secure MasterPass 65 |

66 |  67 |

The MasterPass is used to encrypt the Vault. Thus, the strength of the Vault relies on the strength of your password. Resetting your password will prompt the re-encryption of all the data and discard the former encrypted

68 |
69 |
70 |
71 | 72 | 73 |
74 |
75 | 76 |
77 |
78 | 83 |
84 |
85 |
86 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /static/style/setup.css: -------------------------------------------------------------------------------- 1 | @import "../../bower_components/normalize-css/normalize.css";@keyframes colorTrans{from{border-bottom:1px solid #DDDDDD}to{border-bottom:1px solid #333333}}body{font-family:"Roboto","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,"Lucida Grande",sans-serif;font-weight:300;margin:0;padding:0;background-color:#FFFFFF;width:100%;height:100vh;overflow:hidden}p{margin:0}div.none{display:none}.left{-webkit-align-self:flex-start;align-self:flex-start !important}.right{margin-left:auto !important}button,.button{background-color:#FFFFFF;border:1px solid #DDDDDD;width:100%;padding:.3rem;font-weight:400;outline:none}button:active,.button:active,button:hover,.button:hover{background-color:#DDDDDD}button.fancy{margin-top:.2rem;border:none;color:#FFFFFF;width:30% !important;background:linear-gradient(to right, #EEA849, #F46B45);background-size:200% 200%;animation:OrangeAnimGrad 3s ease infinite}button.fancy:active,button.fancy:hover{opacity:.8}img.info{padding-left:.2rem;height:.8rem}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;transition:max-height .5s,padding .3s;background-color:#DDDDDD;font-size:.8rem}img.info:hover+p.info{max-height:100%;padding:.2rem}.moveUp-enter{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 100%, 0);z-index:10000}.moveUp-enter.moveUp-enter-active{transform:translate3d(0, 0, 0)}.moveUp-leave{transition-duration:.3s;transition-property:transform,opacity;transition-timing-function:ease-out;transform:translate3d(0, 0, 0);opacity:1}.moveUp-leave.moveUp-leave-active{transform:translate3d(0, -15%, 0);opacity:.3}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Italic.eot');src:url('../fonts/Roboto-Italic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Italic.woff') format('woff'),url('../fonts/Roboto-Italic.ttf') format('truetype');font-weight:normal;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BlackItalic.eot');src:url('../fonts/Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BlackItalic.woff') format('woff'),url('../fonts/Roboto-BlackItalic.ttf') format('truetype');font-weight:900;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Bold.eot');src:url('../fonts/Roboto-Bold.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Bold.woff') format('woff'),url('../fonts/Roboto-Bold.ttf') format('truetype');font-weight:bold;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Thin.eot');src:url('../fonts/Roboto-Thin.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Thin.woff') format('woff'),url('../fonts/Roboto-Thin.ttf') format('truetype');font-weight:100;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Medium.eot');src:url('../fonts/Roboto-Medium.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Medium.woff') format('woff'),url('../fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Light.eot');src:url('../fonts/Roboto-Light.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Light.woff') format('woff'),url('../fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Regular.eot');src:url('../fonts/Roboto-Regular.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Regular.woff') format('woff'),url('../fonts/Roboto-Regular.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-ThinItalic.eot');src:url('../fonts/Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-ThinItalic.woff') format('woff'),url('../fonts/Roboto-ThinItalic.ttf') format('truetype');font-weight:100;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-BoldItalic.eot');src:url('../fonts/Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-BoldItalic.woff') format('woff'),url('../fonts/Roboto-BoldItalic.ttf') format('truetype');font-weight:bold;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-Black.eot');src:url('../fonts/Roboto-Black.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-Black.woff') format('woff'),url('../fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-MediumItalic.eot');src:url('../fonts/Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-MediumItalic.woff') format('woff'),url('../fonts/Roboto-MediumItalic.ttf') format('truetype');font-weight:500;font-style:italic}@font-face{font-family:'Roboto';src:url('../fonts/Roboto-LightItalic.eot');src:url('../fonts/Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),url('../fonts/Roboto-LightItalic.woff') format('woff'),url('../fonts/Roboto-LightItalic.ttf') format('truetype');font-weight:300;font-style:italic}@keyframes colorTrans{from{background-color:#FFFFFF}to{background-color:#DDDDDD}}@-webkit-keyframes OrangeAnimGrad{0%{background-position:0 51%}50%{background-position:100% 50%}100%{background-position:0 51%}}@keyframes OrangeAnimGrad{0%{background-position:0 51%}50%{background-position:100% 50%}100%{background-position:0 51%}}#setup{height:100%;width:100%;text-align:center;overflow:hidden}form{margin:0}header{margin:0}header p{color:#222222}header .minimal h1{margin-top:1rem;font-weight:300}h1{font-size:1.4rem;margin-bottom:.4rem;font-weight:400}p{margin:0;color:#9D9D9D}h1+p{margin:0 2rem}.panel-container{position:relative}.panel-container>div{position:absolute;text-align:center;transform:translateX(-110%);transition:transform .5s}.panel-container>div>button{margin-top:1rem}.panel-container>div.current{width:100%;height:100vh;overflow:hidden;transform:none;position:relative}.panel-container>div.current~div{transform:translateX(110%)}.panel-container header{margin-top:2rem}.right{margin-left:auto !important}img.icon{width:1.4rem;height:1.4rem}h3{margin:.5rem 0;font-weight:normal}a{font-size:.8rem;color:#222222;text-decoration:none;outline:none}a.csp{padding:.6rem 0 !important}a.csp img{height:1.6rem;widht:auto}footer.credit{text-align:center;display:flex;align-items:center;font-size:.8rem;justify-content:center}footer.credit img{height:1rem !important}footer{display:flex;clear:both;position:absolute;border-top:1px solid #DDDDDD;width:100%;padding-bottom:0;background-color:#FFFFFF;bottom:0;left:0}footer>a{float:right;padding:.2rem}a.back{float:left}a.back>img{height:1rem;width:auto}.himg{width:9rem;height:auto;z-index:1000}p.intrfo{color:#9D9D9D;font-size:.8rem;margin:.4rem}div.list{width:100%;overflow:auto}div.item>a{display:flex;align-items:center;border-bottom:1px solid #DDDDDD;padding:.4rem 0;text-align:left}div.name{font-size:1.2rem;margin-left:.4rem;font-weight:300}p.info{display:block;width:100%;box-sizing:border-box;max-height:0;overflow:hidden;padding:0 .5rem;transition:max-height .3s,padding .3s;background-color:#efefef;font-size:.8rem}img.info{float:right;height:.9rem}img.info:hover+p.info{max-height:10rem;padding-top:.5rem;padding-bottom:.5rem}input{width:98%}input[type=password]{margin-top:1rem;border:none;border-bottom:1px solid #DDDDDD;outline:none}input[type=password]:focus{border-bottom:1px solid #333333}input[type=submit]{margin-top:1rem;height:2rem;font-weight:normal;background-color:#DDDDDD;border:1px solid #DDDDDD;width:100%;outline:none}input[type=submit]:focus{border:1px solid #333333}div.submit{text-align:right;background-color:#FFFFFF;width:100%}.none{display:none}.banner{margin:1rem auto 0;position:relative;align-items:center;justify-content:center;width:100%}div#panel-default>header .banner{margin:2rem auto 0;position:relative;display:inline-block;width:50%;z-index:-1;color:#DDDDDD}div#panel-default>header .himg{z-index:1000}.banner-left{margin-left:-3rem;float:left}.banner-right{margin-right:-3rem;float:right}.marquee{overflow:hidden;position:absolute}.marquee-1{visibility:hidden}.marquee-2{visibility:hidden}.marquee.visible{visibility:visible}div.item.err>div{display:none;margin-top:.5rem;margin-left:0;width:100%;font-size:.8rem;padding:.4rem 0;background-color:#F05A5C;color:#FFFFFF}section.accounts{width:60%;margin:auto}section.accounts>header{border-bottom:1px solid #DDDDDD}.spinner{-webkit-animation:rotator 1.4s linear infinite;animation:rotator 1.4s linear infinite}@-webkit-keyframes rotator{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@keyframes rotator{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}.path{stroke-dasharray:187;stroke-dashoffset:0;-webkit-transform-origin:center;transform-origin:center;-webkit-animation:dash 1.4s ease-in-out infinite,colors 5.6s ease-in-out infinite;animation:dash 1.4s ease-in-out infinite,colors 5.6s ease-in-out infinite}@-webkit-keyframes colors{0%{stroke:#EEA849}50%{stroke:#F46B45}100%{stroke:#EEA849}}@keyframes colors{0%{stroke:#EEA849}50%{stroke:#F46B45}100%{stroke:#EEA849}}@-webkit-keyframes dash{0%{stroke-dashoffset:187}50%{stroke-dashoffset:46.75;-webkit-transform:rotate(135deg);transform:rotate(135deg)}100%{stroke-dashoffset:187;-webkit-transform:rotate(450deg);transform:rotate(450deg)}}@keyframes dash{0%{stroke-dashoffset:187}50%{stroke-dashoffset:46.75;-webkit-transform:rotate(135deg);transform:rotate(135deg)}100%{stroke-dashoffset:187;-webkit-transform:rotate(450deg);transform:rotate(450deg)}}#masterpassprompt{height:100%;min-height:20rem;width:60%;margin:auto}#masterpassprompt>button{margin:.5rem 0;font-weight:normal;width:100%}#masterpassprompt p.note{margin:none;font-size:.8rem}div.forgotMP{padding:.2rem .2rem 0 0;text-align:right}div.masterpass>label{display:inline-block;font-size:.8rem;margin:.2rem 0;color:#F05A5C}.invalid{border-color:#F05A5C !important} -------------------------------------------------------------------------------- /static/vault.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | The Vault 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 | 31 |
32 |
33 |
34 | 35 | 52 | 53 | 59 | 111 | 112 | 121 | 122 | 126 | 127 | 254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /static/style/setup.less: -------------------------------------------------------------------------------- 1 | // out: ./setup.css, compress: true 2 | /* Setup styles 3 | ========================================================================== 4 | */ 5 | @import (less) "mixins.less"; 6 | /* Variable declarations*/ 7 | @border-width: 2px; 8 | @side-margin: 0.8rem; 9 | @section-width: 60%; 10 | @name-fsize: 1rem; 11 | @header-fsize: 1rem; 12 | @spacing04: 0.4rem; 13 | @spacing-ic-txt: @side-margin - 0.4rem; 14 | @lastMod-fsize: 0.8rem; 15 | @ic-size: 1.4rem; 16 | @win-height: 100vh; 17 | /* TODO: ADD MARGIN RELATIVELY/CONTEXTUALLY TO CORE ELEMENTS I.E. for a button, use panel-container > button*/ 18 | /* Animations */ 19 | @keyframes colorTrans { 20 | from { 21 | background-color: @white; 22 | } 23 | to { 24 | background-color: @light; 25 | } 26 | } 27 | @-webkit-keyframes OrangeAnimGrad { 28 | 0% { 29 | background-position: 0 51%; 30 | } 31 | 50% { 32 | background-position: 100% 50%; 33 | } 34 | 100% { 35 | background-position: 0 51%; 36 | } 37 | } 38 | @keyframes OrangeAnimGrad { 39 | 0% { 40 | background-position: 0 51%; 41 | } 42 | 50% { 43 | background-position: 100% 50%; 44 | } 45 | 100% { 46 | background-position: 0 51%; 47 | } 48 | } 49 | /* General styles */ 50 | #setup { 51 | height : 100%; 52 | width : 100%; 53 | text-align: center; 54 | overflow : hidden; 55 | } 56 | form { 57 | margin: 0; 58 | } 59 | header { 60 | margin: 0; 61 | p { 62 | color: @blacker; 63 | } 64 | .minimal { 65 | h1 { 66 | margin-top : 1rem; 67 | font-weight: 300; 68 | } 69 | } 70 | } 71 | h1 { 72 | font-size : 1.4rem; 73 | margin-bottom: 0.4rem; 74 | font-weight : 400; 75 | } 76 | p { 77 | margin: 0; 78 | color : @dark; 79 | } 80 | h1 + p { 81 | margin: 0 2rem; 82 | } 83 | .panel-container { 84 | position: relative; 85 | & > div { 86 | position : absolute; 87 | text-align: center; 88 | transform : translateX(-110%); 89 | transition: transform 0.5s; 90 | & > button { 91 | margin-top: 1rem; 92 | } 93 | } 94 | & > div.current { 95 | width : 100%; 96 | height: 100vh; 97 | overflow : hidden; 98 | transform: none; 99 | position : relative; 100 | } 101 | & > div.current ~ div { 102 | transform: translateX(110%); 103 | } 104 | header { 105 | margin-top: 2rem; 106 | } 107 | } 108 | 109 | // .panel-container > div { 110 | // position: absolute; 111 | // text-align: center; 112 | // transform: translateX(-110%); 113 | // transition: transform 0.5s; 114 | // } 115 | // .panel-container > div > footer { 116 | // transform: translateX(-110%); 117 | // } 118 | // 119 | // .panel-container > div.current > footer { 120 | // transform: translateX(100%); 121 | // } 122 | /* TODO DISABLE ANIMATION ON FIRST PANE */ 123 | // #panel-default ~ div { 124 | // transform: none; 125 | // } 126 | // #panel-default > div { 127 | // transform: none; 128 | // transition: none; 129 | // } 130 | .right { 131 | margin-left: auto !important; 132 | } 133 | img.icon { 134 | width : @ic-size; 135 | height: @ic-size; 136 | } 137 | h3 { 138 | margin : 0.5rem 0; 139 | font-weight: normal; 140 | } 141 | a { 142 | 143 | // cursor: hand; 144 | font-size : 0.8rem; 145 | color : @blacker; 146 | text-decoration: none; 147 | outline : none; 148 | } 149 | a.csp { 150 | padding: 0.6rem 0 !important; 151 | img { 152 | height: 1.6rem; 153 | widht : auto; 154 | } 155 | } 156 | footer.credit { 157 | text-align : center; 158 | display : flex; 159 | align-items : center; 160 | font-size : 0.8rem; 161 | justify-content: center; 162 | img { 163 | height: 1rem !important; 164 | } 165 | } 166 | footer { 167 | display : flex; 168 | clear : both; 169 | position : absolute; 170 | border-top : 1px solid @light; 171 | width : 100%; 172 | padding-bottom : 0; 173 | background-color: @white; 174 | bottom : 0; 175 | left : 0; 176 | } 177 | footer > a { 178 | float : right; 179 | padding: 0.2rem; 180 | } 181 | a.back { 182 | float: left; 183 | } 184 | a.back >img { 185 | height: 1rem; 186 | width : auto; 187 | } 188 | .himg { 189 | width : 9rem; 190 | height : auto; 191 | z-index: 1000; 192 | } 193 | p.intrfo { 194 | color: @dark; 195 | font-size: 0.8rem; 196 | margin: 0.4rem; 197 | } 198 | div.list { 199 | width : 100%; 200 | overflow: auto; 201 | } 202 | div.item > a { 203 | display : flex; 204 | align-items : center; 205 | border-bottom: 1px solid @light; 206 | padding : @spacing04 0; 207 | text-align : left; 208 | } 209 | div.name { 210 | font-size : 1.2rem; 211 | margin-left: @spacing-ic-txt; 212 | font-weight: 300; 213 | } 214 | p.info { 215 | display : block; 216 | width : 100%; 217 | box-sizing : border-box; 218 | max-height : 0; 219 | overflow : hidden; 220 | padding : 0 0.5rem; 221 | transition : max-height 0.3s, padding 0.3s; 222 | background-color: #efefef; 223 | font-size : 0.8rem; 224 | } 225 | img.info { 226 | float : right; 227 | height: 0.9rem; 228 | } 229 | img.info:hover + p.info { 230 | max-height : 10rem; 231 | padding-top : 0.5rem; 232 | padding-bottom: 0.5rem; 233 | } 234 | input { 235 | width: 98%; 236 | } 237 | input[type=password] { 238 | margin-top : 1rem; 239 | border : none; 240 | border-bottom: 1px solid @light; 241 | outline : none; 242 | &:focus { 243 | border-bottom: 1px solid @black; 244 | } 245 | } 246 | input[type=submit] { 247 | margin-top : 1rem; 248 | height : 2rem; 249 | font-weight : normal; 250 | background-color: @light; 251 | border : 1px solid @light; 252 | width : 100%; 253 | outline : none; 254 | &:focus { 255 | border: 1px solid @black; 256 | } 257 | } 258 | div.submit { 259 | text-align : right; 260 | background-color: @white; 261 | width : 100%; 262 | } 263 | .none { 264 | display: none; 265 | } 266 | 267 | /* Welcome Panel styles 268 | * ================= 269 | */ 270 | .banner { 271 | margin : 1rem auto 0; 272 | position : relative; 273 | align-items : center; 274 | justify-content: center; 275 | width : 100%; 276 | } 277 | div#panel-default > header { 278 | .banner { 279 | margin : 2rem auto 0; 280 | position: relative; 281 | display : inline-block; 282 | width : 50%; 283 | z-index : -1; 284 | color : @light; 285 | } 286 | .banner + .himg { 287 | 288 | } 289 | .himg { 290 | z-index: 1000; 291 | } 292 | } 293 | .banner-left { 294 | margin-left: -3rem; 295 | float : left; 296 | } 297 | .banner-right { 298 | margin-right: -3rem; 299 | float : right; 300 | } 301 | .marquee { 302 | overflow: hidden; 303 | position: absolute; 304 | } 305 | .marquee-1 { 306 | visibility: hidden; 307 | } 308 | .marquee-2 { 309 | visibility: hidden; 310 | } 311 | .marquee.visible { 312 | visibility: visible; 313 | } 314 | div.item.err > div { 315 | display : none; 316 | margin-top : 0.5rem; 317 | margin-left : 0; 318 | width : 100%; 319 | font-size : 0.8rem; 320 | padding : 0.4rem 0; 321 | background-color: @invalid-color; 322 | color : @white; 323 | } 324 | 325 | /* Accounts Panel styles 326 | * ================= 327 | */ 328 | section.accounts { 329 | 330 | } 331 | section.accounts { 332 | width : @section-width; 333 | margin: auto; 334 | } 335 | section.accounts > header { 336 | border-bottom: 1px solid @light; 337 | } 338 | 339 | /* Auth Panel styles 340 | * ================= 341 | */ 342 | .spinner { 343 | -webkit-animation: rotator 1.4s linear infinite; 344 | animation : rotator 1.4s linear infinite; 345 | } 346 | @-webkit-keyframes rotator { 347 | 0% { 348 | -webkit-transform: rotate(0deg); 349 | transform : rotate(0deg); 350 | } 351 | 100% { 352 | -webkit-transform: rotate(270deg); 353 | transform : rotate(270deg); 354 | } 355 | } 356 | @keyframes rotator { 357 | 0% { 358 | -webkit-transform: rotate(0deg); 359 | transform : rotate(0deg); 360 | } 361 | 100% { 362 | -webkit-transform: rotate(270deg); 363 | transform : rotate(270deg); 364 | } 365 | } 366 | .path { 367 | stroke-dasharray : 187; 368 | stroke-dashoffset : 0; 369 | -webkit-transform-origin: center; 370 | transform-origin : center; 371 | -webkit-animation : dash 1.4s ease-in-out infinite, colors 5.6s ease-in-out infinite; 372 | animation : dash 1.4s ease-in-out infinite, colors 5.6s ease-in-out infinite; 373 | } 374 | @-webkit-keyframes colors { 375 | 0% { 376 | stroke: @orange; 377 | } 378 | 50% { 379 | stroke: @orange_d; 380 | } 381 | 100% { 382 | stroke: @orange; 383 | } 384 | } 385 | @keyframes colors { 386 | 0% { 387 | stroke: @orange; 388 | } 389 | 50% { 390 | stroke: @orange_d; 391 | } 392 | 100% { 393 | stroke: @orange; 394 | } 395 | } 396 | @-webkit-keyframes dash { 397 | 0% { 398 | stroke-dashoffset: 187; 399 | } 400 | 50% { 401 | stroke-dashoffset: 46.75; 402 | -webkit-transform: rotate(135deg); 403 | transform : rotate(135deg); 404 | } 405 | 100% { 406 | stroke-dashoffset: 187; 407 | -webkit-transform: rotate(450deg); 408 | transform : rotate(450deg); 409 | } 410 | } 411 | @keyframes dash { 412 | 0% { 413 | stroke-dashoffset: 187; 414 | } 415 | 50% { 416 | stroke-dashoffset: 46.75; 417 | -webkit-transform: rotate(135deg); 418 | transform : rotate(135deg); 419 | } 420 | 100% { 421 | stroke-dashoffset: 187; 422 | -webkit-transform: rotate(450deg); 423 | transform : rotate(450deg); 424 | } 425 | } 426 | 427 | /* MasterPass Panel styles 428 | * ================= 429 | */ 430 | #masterpassprompt { 431 | height : 100%; 432 | min-height: 20rem; 433 | width : @section-width; 434 | margin : auto; 435 | } 436 | #masterpassprompt > button { 437 | margin : 0.5rem 0; 438 | font-weight: normal; 439 | width : 100%; 440 | } 441 | #masterpassprompt p.note { 442 | margin : none; 443 | font-size: 0.8rem; 444 | } 445 | div.forgotMP { 446 | padding : 0.2rem 0.2rem 0 0; 447 | text-align: right; 448 | } 449 | 450 | /* INVALID STYLING */ 451 | div.masterpass > label { 452 | display : inline-block; 453 | font-size: 0.8rem; 454 | margin : 0.2rem 0; 455 | color : @invalid-color; 456 | } 457 | .invalid { 458 | border-color: @invalid-color !important; 459 | } 460 | --------------------------------------------------------------------------------