├── .babelrc ├── .bowerrc ├── .editorconfig ├── .eslintignore ├── .gitattributes ├── .gitignore ├── .yo-rc.json ├── README.md ├── app ├── apple-touch-icon.png ├── davemail.json ├── favicon.ico ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── images │ ├── davemail-login.jpg │ ├── davemail-logo.png │ ├── davemail.png │ ├── noise │ │ ├── noise-loud.png │ │ ├── noise-soft.png │ │ └── noise.png │ ├── paisley │ │ ├── paisley-lg-100.png │ │ ├── paisley-lg-loud.png │ │ ├── paisley-lg-soft.png │ │ ├── paisley-lg.png │ │ ├── paisley-loud.png │ │ ├── paisley-soft.png │ │ └── paisley.png │ └── pinstripe │ │ ├── pinstripe-lg-loud.png │ │ ├── pinstripe-lg-soft.png │ │ ├── pinstripe-lg-xloud.png │ │ ├── pinstripe-lg.png │ │ ├── pinstripe-loud.png │ │ ├── pinstripe-md-xloud.png │ │ ├── pinstripe-sm-loud.png │ │ ├── pinstripe-sm-soft.png │ │ ├── pinstripe-sm-xloud.png │ │ ├── pinstripe-sm.png │ │ ├── pinstripe-soft.png │ │ └── pinstripe.png ├── index.html ├── robots.txt ├── scripts │ └── main.js └── styles │ ├── davemail │ └── style.scss │ └── main.scss ├── bower.json ├── dist ├── apple-touch-icon.png ├── davemail.json ├── favicon.ico ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── images │ ├── davemail-login.jpg │ ├── davemail-logo.png │ ├── davemail.png │ ├── noise │ │ ├── noise-loud.png │ │ ├── noise-soft.png │ │ └── noise.png │ ├── paisley │ │ ├── paisley-lg-100.png │ │ ├── paisley-lg-loud.png │ │ ├── paisley-lg-soft.png │ │ ├── paisley-lg.png │ │ ├── paisley-loud.png │ │ ├── paisley-soft.png │ │ └── paisley.png │ └── pinstripe │ │ ├── pinstripe-lg-loud.png │ │ ├── pinstripe-lg-soft.png │ │ ├── pinstripe-lg-xloud.png │ │ ├── pinstripe-lg.png │ │ ├── pinstripe-loud.png │ │ ├── pinstripe-md-xloud.png │ │ ├── pinstripe-sm-loud.png │ │ ├── pinstripe-sm-soft.png │ │ ├── pinstripe-sm-xloud.png │ │ ├── pinstripe-sm.png │ │ ├── pinstripe-soft.png │ │ └── pinstripe.png ├── index.html ├── robots.txt ├── scripts │ ├── main.js │ ├── plugins.js │ ├── vendor.js │ └── vendor │ │ └── modernizr.js └── styles │ ├── main.css │ └── vendor.css ├── gulpfile.babel.js ├── package.json └── test ├── index.html └── spec └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [{package,bower}.json] 24 | indent_style = space 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | app/scripts/main.js -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # dist 3 | .tmp 4 | .sass-cache 5 | bower_components 6 | test/bower_components 7 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-mocha": {} 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Davemail 2 | 3 | 4 | 5 | Decentralised, encrypted, anonymous, offline messaging platform for git. Using the git [distributed version control](https://en.wikipedia.org/wiki/Distributed_version_control#Distributed_vs._centralized) system for encrypted messaging. 6 | 7 | ## Mission Statement 8 | 9 | Empowering you to take back your communication privacy. 10 | 11 | ## Quick Start! 12 | 13 | Clone or download this repository and open `dist/index.html`. Simple! 14 | 15 | ## SMTP email problems 16 | 17 | [SMTP email](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol) is one of the oldest technologies on the internet. Emails are sent in plain text accross the internet so anyone listening in can read them. [Edward Snowden](https://en.wikipedia.org/wiki/Edward_Snowden) has revealed that the largest email platforms in the world are in league with government spies with little regard for the fundamental right to privacy, recognized in the UN Declaration of Human Rights. 18 | 19 | ## PGP encryption problems 20 | 21 | [Pretty Good Privacy (PGP)](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) is a solution to some of the problems with SMTP email as the email body is encrypted. However the PGP key pair is created [nondeterministically](https://en.wikipedia.org/wiki/Nondeterministic_algorithm) so the private key must be saved and stored securely in order to decrypt messages. The email metadata (sender, recievers, subject, time) is still prone to interception and mass survailance. 22 | 23 | ## Scrypt and RSA Encrypted Davemail 24 | 25 | Davemail is an alternative to SMTP email. Data is stored in json format with user data separated from the encrypted message data. The json data is open source and decentralised using [git](https://en.wikipedia.org/wiki/Git_(software)) but it is impossible for anyone to deduce which encrypted message was sent to or from which users (unless you hold the key to messages sent to you). 26 | 27 | RSA keys are generated [deterministically](https://en.wikipedia.org/wiki/Deterministic_algorithm) so it is possible to restore long private keys using a strong and memorable passphrase. No need to save and secure a private key on a local machine. 28 | 29 | The [https://github.com/Tarsnap/scrypt](Scrypt) key derivation function makes brute-force attacks costly. Scrypt is applied to all passwords before the RSA keys are generated. 30 | 31 | The Davemail application makes reading and sending encrypted messages easy, hiding the encryption process to improve the user experience. The Davemail application also works offline, so your passphrase can be protected from hackers using keyloggers or screen capture attacks. 32 | 33 | 34 | 35 | ## Decentralisation and anonymity 36 | 37 | This git repository can be cloned and hosted on any computer connected to the internet. SSH access details to these git repositories can be published in the json file, anonymising users. Git repository owners can take responsibility for reducing spam by limiting the frequency of commits. 38 | 39 | ## Example davemail.json file 40 | 41 | ``` 42 | { 43 | "davemail": { 44 | "users": { 45 | "davidapple": { 46 | "publicKey": "b8swlmHX6fsc1lSMRjXOqQoYjGf/vtu0wEy4TKudKtpDJ9MzYlg+V1OCpNFZEKq22sYGHjvazxLqy9ugz4nhVAmAMmuYFRukMW1OcNzjdCEu4sno5hUPoSHr0cJb4T2rQl7Tc1dThJmpCbE9NRPA1FZx5XVMhCmiOBTwU+pW0l6BBj+jl2nFeyndknwL/WdN47UEj4Um5yfx/5+I/LS4EIUlme1fkEYe5XjCaM3zFN1UFUw4nDih4MUKrjEE7n2/" 47 | }, 48 | "tinyi": { 49 | "publicKey": "nQOZN7PF0Qr5to0xpF6iWGGRU0Yqm4S/0OZVjkx4dldg6+XlxzeJNYQheTh/CTaqiRzVxyUCEekcsVxabGtx9K6xEIVRFP2okGOXYu7zJMKQHf25hW4nWLS/34DJRTibxkq1VzgJ6nlVMwOdUjr0sgqK6vI3X7iEyBKe76I0m610Y2q9hvxNOg+MBQ64dJjdx2wCF9LitxGXy1DaQCa420RE86sHwK9yMrH3mNVRqGmVRX5KkeS2QhHdXwoe4bxV" 50 | } 51 | }, 52 | "emails": [ 53 | { 54 | "time": "2016-04-11T09:48:41.751Z", 55 | "cipher": "Wn/Oj5fSf+IRPwYYjazM2tpOzRPe81memxXSPqmSGx4eXZkIzVsoPnaMohwTLga8hVNvV6GJan+ZroiDDjD8Kw9MoP+zULmTE1PoI27p/qgSMKBHf7S8mTOvpm5+CzaMjfQhqJ6DcRibnQSQgfKLjn06QjtHt2v9qD0hlKODLrhhVy5m8ShgEHI6/TOyXW3/w/y0NZStPVY8gCJNO1F+zlMsX9QhRYV7XZ8TCExkLdsB3lO6iG7RhxMflb/iMukm?TuyIKKX1YcSQlTQhCOhjxhR2jwjhDD/Z16/xR1lzlg/CjrzbMlsF/p0HoOBZTEcU8Jq+vZ6u/P0I/x20v99P3A==" 56 | }, 57 | { 58 | "time": "2016-04-11T09:52:22.194Z", 59 | "cipher": "hltRGEkeFR7zWubXdIspvJtte+/cGHmBnhGvM8U8roTeYA86GuyfVSFDEXhCwipxPtAM0jJmrFpLHBY/51QOf+uHjNxMBxMob+NOme8kiiw3plJeD1Tqv/MwoDWzhA8TQRxvdUPAEjo1BC1wVLFgra30Aw3sblL7UYQnPjcXPDdwFLcRZ+HbMdCqYf3z1fdXvEv7LEoYwSkVivGmdJ520MmVpPzcC+WqXv9I/GuU8oau3CYKJEotZklCIVz0j/u+?NbANPCDdSQvC4HpNXEzZo3HlAAhaxcOlSlkO19x5a3WbOTscl0aYkeXiAdkv5XK2xXPk+uPpwQWOl0ucO4eyDQ==" 60 | } 61 | ], 62 | "servers": [ 63 | { 64 | "ssh": "git@github.com:davidapple/davemail.git", 65 | "username": "anonymous", 66 | "password": "example", 67 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4LojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4kYjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9EzSdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myivO7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPqdAv8JggJICUvax2T9va5 gsg-keypair" 68 | } 69 | ] 70 | } 71 | } 72 | ``` 73 | 74 | ## Development 75 | Originally created using [Yeoman Webapp Generator](https://github.com/yeoman/generator-webapp). 76 | 77 | ## Getting Started 78 | 79 | - Run `npm install` to install Node Package Manager dependencies 80 | - Run `bower install` to install frontend dependencies 81 | - Run `gulp serve` to preview and watch for changes 82 | - Run `gulp serve:test` to run the tests in the browser 83 | - Run `gulp` to build your webapp for production 84 | - Run `gulp serve:dist` to preview the production build 85 | 86 | ## MIT License 87 | 88 | Copyright (c) 2016 Davemail 89 | 90 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 91 | 92 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 93 | 94 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 95 | -------------------------------------------------------------------------------- /app/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/apple-touch-icon.png -------------------------------------------------------------------------------- /app/davemail.json: -------------------------------------------------------------------------------- 1 | { 2 | "davemail": { 3 | "users": { 4 | "tinyi": { 5 | "publicKey": "Waa5H1sVsFmPuDqSZFKMPOgPSmhUQMtcoIaQA87iryXJVH3jhYueW+qIBBOo2x2JNzd05Pm3gJqrFHnFXnJA5UfNIIQlWn6wbxnfced/JRcE2fS0FmrLH+XDB6xms5/ZX+ZzGRKNTOJtk/WNhJSSQsYWa3DbkqZgLMw4m3go9gVeSYN0Isjo2hhQ3fKeW+MrAoaynyRHA6s5OB4I5E/Af71TeqmsLNGl4dlcqYa+ameh6e/PiiKJw6x3SWJJAbYn" 6 | }, 7 | "davidapple": { 8 | "publicKey": "TCQy+rIxLzvd0MDap6CT0ZTxZnKQiT9bNyRzr63Ob77Yxe3zUkGNR/qDxhMMNVgZjvFDEA+Z5lnMx+YHCdLni3pN4Ssj4waS+VuixBHRxU90PFLy/pWK08rOf5pEicCStdSQbfe7MQupQN3CUnBCK9gzG7H8RoVBP3pzy4yAv1us7GC+7+urMfxdz1YoZwGOK99okhcXGnb49w2I9B1Aj0qwjVLMTlRypdgikVCEBwLthcbTSSekCDBSyv/296zF" 9 | } 10 | }, 11 | "emails": [ 12 | { 13 | "time": "2016-05-05T11:14:51.446Z", 14 | "cipher": "Gp4xk6E6NFpm48nHWRHOx1qVRdOtgdZ/lKHBcu8IYA5bFvwf+tUrhNNy+YjyjGRZ8amDubTJzrT+PMFlNm/gbIwho5SbSozMS5qAszscHfXOr3vT2S9NJsbAjm+D8/RdmJI0ZA7omP7ENEBH6VBHMWoDMGfJ/685ic63Bah/wEKBWMk6oL2NtWNVwEiDtwxta72US0oBodzWzKfDSbe+HTuwzcgqL8Grt7YGMsPeZgqO/xyMc9BXcqAGDjY+YLVT?TR2VnwLHpi6j0ofBrFRagI4oEoBczrYnXpaVTfNpRu+NuSnr7vr4ClWpyqWczHi1FzGXzDWFacLVapbaOhYEX142TQCVknCseUCekMWx7bjeRx/8EmN62JVwCRQjq2EE/qKIaxjK7CIByQ+sQPCRmndSzS6D6FUqgRNrNuEgLZAAjWoZbdgEX6vg0P9cHXJ9dznoka3R2sjKiPSPCJRajAqH2eQbEMNGFe5GyfCAxqUx34ryzALYFXq3ZN8wLN0Vx/Ou98mCu0Kqp1XJBWL6qg==" 15 | } 16 | ], 17 | "servers": [ 18 | { 19 | "ssh": "git@github.com:davidapple/davemail.git", 20 | "username": "anonymous", 21 | "password": "example", 22 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4LojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4kYjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9EzSdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myivO7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPqdAv8JggJICUvax2T9va5 gsg-keypair" 23 | } 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/favicon.ico -------------------------------------------------------------------------------- /app/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /app/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /app/images/davemail-login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/davemail-login.jpg -------------------------------------------------------------------------------- /app/images/davemail-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/davemail-logo.png -------------------------------------------------------------------------------- /app/images/davemail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/davemail.png -------------------------------------------------------------------------------- /app/images/noise/noise-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/noise/noise-loud.png -------------------------------------------------------------------------------- /app/images/noise/noise-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/noise/noise-soft.png -------------------------------------------------------------------------------- /app/images/noise/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/noise/noise.png -------------------------------------------------------------------------------- /app/images/paisley/paisley-lg-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley-lg-100.png -------------------------------------------------------------------------------- /app/images/paisley/paisley-lg-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley-lg-loud.png -------------------------------------------------------------------------------- /app/images/paisley/paisley-lg-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley-lg-soft.png -------------------------------------------------------------------------------- /app/images/paisley/paisley-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley-lg.png -------------------------------------------------------------------------------- /app/images/paisley/paisley-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley-loud.png -------------------------------------------------------------------------------- /app/images/paisley/paisley-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley-soft.png -------------------------------------------------------------------------------- /app/images/paisley/paisley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/paisley/paisley.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-lg-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-lg-loud.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-lg-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-lg-soft.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-lg-xloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-lg-xloud.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-lg.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-loud.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-md-xloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-md-xloud.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-sm-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-sm-loud.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-sm-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-sm-soft.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-sm-xloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-sm-xloud.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-sm.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe-soft.png -------------------------------------------------------------------------------- /app/images/pinstripe/pinstripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/app/images/pinstripe/pinstripe.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Davemail 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 53 | 54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 | 62 |

Davemail

63 |

Decentralised, deterministic RSA encrypted, anonymous, offline email for git.

64 |
65 |
66 |
67 |
68 | 69 |
70 | 71 | 92 | 93 |
94 | 95 |
96 |
97 |

Sign In

98 | 99 |
100 | 101 |
102 |
103 | Sign Up 104 |
105 |
106 | 107 | 108 |
109 |
110 | 111 | 115 |
116 | 117 |
118 |
119 | 120 |
121 |
122 |
123 |

Under the hood

124 |

The sign in button generates a RSA key pair on your local machine (see browser console).

125 |
126 |
127 |
128 | 129 |
130 | 131 | 192 | 193 | 220 | 221 | 231 | 232 | 274 | 275 | 279 |
280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /app/scripts/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function(){ 4 | window.davemail = new Object(); 5 | davemail.info = 'Davemail 2.0.0 by David Apple https://github.com/davidapple/davemail Donate Bitcoin to 13D3A8PP91MLF5VTBQMH5HG76F42RNRF28'; 6 | 7 | var scrypt = scrypt_module_factory(); // https://github.com/tonyg/js-scrypt 8 | 9 | // - Functions 10 | function loadDavemail(){ 11 | return $.getJSON('davemail.json', function() { 12 | console.log('davemail.json loaded confirmation one'); 13 | }) 14 | .done(function() { 15 | console.log('davemail.json loaded confirmation two'); 16 | }) 17 | .fail(function( jqxhr, textStatus, error ) { 18 | var err = textStatus + ", " + error; 19 | console.log('davemail.json failed to load: ' + err ); 20 | importPage(); 21 | }); 22 | } 23 | 24 | function loadDavemailAgain(davemail){ 25 | var newDavemail = $.getJSON('davemail.json', function() { 26 | console.log('davemail.json loaded confirmation one'); 27 | }) 28 | .done(function(response) { 29 | console.log('davemail.json loaded confirmation two'); 30 | if(_.isEqual(davemail.jsonData.responseJSON, response)){ 31 | $('#signUpReplaceDownload').remove(); 32 | $('#signUpButton').show(); 33 | $('#signingUpLoader').hide(); 34 | $('#fileReplacedButton').show(); 35 | $('#fileReplacedLoader').hide(); 36 | $('#usernameHeading').text(davemail.username); 37 | messagesPage(); 38 | davemail.messages = mapMessages(davemail); 39 | buildMessagesTable(davemail); 40 | }else{ 41 | $('#fileNotReplacedWarning').show(); 42 | $('#fileReplacedLoader').hide(); 43 | $('#fileReplacedButton').show(); 44 | } 45 | }) 46 | .fail(function( jqxhr, textStatus, error ) { 47 | var err = textStatus + ", " + error; 48 | console.log('davemail.json failed to load: ' + err ); 49 | 50 | // Let the user progress in the hope that they have successfully replaced their json file 51 | $('#signUpReplaceDownload').remove(); 52 | $('#signUpButton').show(); 53 | $('#signingUpLoader').hide(); 54 | $('#fileReplacedButton').show(); 55 | $('#fileReplacedLoader').hide(); 56 | $('#usernameHeading').text(davemail.username); 57 | messagesPage(); 58 | davemail.messages = mapMessages(davemail); 59 | buildMessagesTable(davemail); 60 | 61 | }); 62 | } 63 | 64 | function composeInit(davemail){ 65 | $('#composeToList li').remove(); 66 | var usersArray = _.map(davemail.jsonData.responseJSON.davemail.users, function(num, key){ 67 | $('
  • ').text(key).click(function(event){ 68 | $('#composeTo').val(key); 69 | $('#composeTo').removeClass('invalid'); 70 | $('#composePublicKey').val(num.publicKey); 71 | $('#composeToListWrapper').hide(); 72 | $('#composeSendButton').show(); 73 | }).appendTo('#composeToList'); 74 | return key; 75 | }); 76 | var filter = $('#composeTo'), clearfilter = $('input#clearfilter'); 77 | $('#composeToList').listfilter({ 78 | 'filter': filter, 79 | 'clearlink': clearfilter, 80 | 'alternate': true, 81 | 'alternateclass': 'other' 82 | }); 83 | $('#composeTo').keyup(function(){ 84 | if($('#composeTo').val().length > 0){ 85 | $('#composeToListWrapper').show(); 86 | if($('#composeToList li:visible').length == 0){ 87 | $('#composeToListWrapper').hide(); 88 | } 89 | if(_.indexOf(usersArray, $('#composeTo').val()) == -1){ 90 | $('#composePublicKey').val(''); 91 | $('#composeSendButton').hide(); 92 | }else{ 93 | $('#composePublicKey').val(davemail.jsonData.responseJSON.davemail.users[$('#composeTo').val()].publicKey); 94 | $('#composeSendButton').show(); 95 | } 96 | }else{ 97 | $('#composeToListWrapper').hide(); 98 | } 99 | }).focusout(function(){ 100 | setTimeout(function (){ 101 | if(_.indexOf(usersArray, $('#composeTo').val()) == -1){ 102 | $('#composeTo').addClass('invalid'); 103 | }else{ 104 | $('#composeTo').removeClass('invalid'); 105 | $('#composeToListWrapper').hide(); 106 | } 107 | }, 10); 108 | }); 109 | $('#composePublicKeyButton').click(function(){ 110 | if ($(this).prop('checked')){ 111 | $('#composeShowPublicKey').show(); 112 | }else{ 113 | $('#composeShowPublicKey').hide(); 114 | } 115 | }); 116 | } 117 | 118 | function importPage(event){ 119 | if(_.isObject(event)){ 120 | event.preventDefault(); 121 | } 122 | $('#importDavemail').show(); 123 | $('nav').hide(); 124 | $('#signIn').hide(); 125 | $('#signUp').hide(); 126 | $('#messages').hide(); 127 | $('#signUpReplace').hide(); 128 | $('#navSignInButton').parent().removeClass('active'); 129 | $('#navSignUpButton').parent().removeClass('active'); 130 | $('#navMessagesButton').parent().removeClass('active'); 131 | } 132 | function signInPage(event){ 133 | if(_.isObject(event)){ 134 | event.preventDefault(); 135 | } 136 | $('#signIn').show(); 137 | $('#signUp').hide(); 138 | $('#messages').hide(); 139 | $('#signUpReplace').hide(); 140 | $('#navSignInButton').parent().addClass('active'); 141 | $('#navSignUpButton').parent().removeClass('active'); 142 | $('#navMessagesButton').parent().removeClass('active'); 143 | } 144 | function signUpPage(event){ 145 | if(_.isObject(event)){ 146 | event.preventDefault(); 147 | } 148 | $('#signUp').show(); 149 | $('#signIn').hide(); 150 | $('#messages').hide(); 151 | $('#navSignUpButton').parent().addClass('active'); 152 | $('#navSignInButton').parent().removeClass('active'); 153 | $('#navMessagesButton').parent().removeClass('active'); 154 | } 155 | function messagesPage(event){ 156 | if(_.isObject(event)){ 157 | event.preventDefault(); 158 | } 159 | $('#messages').show(); 160 | $('#compose').hide(); 161 | $('#signIn').hide(); 162 | $('#signUp').hide(); 163 | $('#signUpReplace').hide(); 164 | $('#navMessagesButton').show(); 165 | $('#navMessagesButton').parent().addClass('active'); 166 | $('#navComposeButton').show(); 167 | $('#navComposeButton').parent().removeClass('active'); 168 | $('#navSignInButton').parent().removeClass('active'); 169 | $('#navSignUpButton').parent().removeClass('active'); 170 | $('#navSignOutButton').show(); 171 | $('#navSignInButton').hide(); 172 | $('#navSignUpButton').hide(); 173 | $('.jumbotron').hide(); 174 | } 175 | function composePage(event){ 176 | if(_.isObject(event)){ 177 | event.preventDefault(); 178 | } 179 | $('#messages').hide(); 180 | $('#compose').show(); 181 | $('#signIn').hide(); 182 | $('#signUp').hide(); 183 | $('#signUpReplace').hide(); 184 | $('#navMessagesButton').show(); 185 | $('#navMessagesButton').parent().removeClass('active'); 186 | $('#navComposeButton').show(); 187 | $('#navComposeButton').parent().addClass('active'); 188 | $('#navSignInButton').parent().removeClass('active'); 189 | $('#navSignUpButton').parent().removeClass('active'); 190 | $('#navSignOutButton').show(); 191 | $('#navSignInButton').hide(); 192 | $('#navSignUpButton').hide(); 193 | $('.jumbotron').hide(); 194 | } 195 | function signOutPage(event){ 196 | if(_.isObject(event)){ 197 | event.preventDefault(); 198 | } 199 | $('#signIn').show(); 200 | $('#signInButton').show(); 201 | $('#messages').hide(); 202 | $('#compose').hide(); 203 | $('#signUp').hide(); 204 | $('#signUpReplace').hide(); 205 | $('#navComposeButton').hide(); 206 | $('#navMessagesButton').hide(); 207 | $('#navSignInButton').parent().addClass('active'); 208 | $('#navComposeButton').parent().removeClass('active'); 209 | $('#navMessagesButton').parent().removeClass('active'); 210 | $('#navSignUpButton').parent().removeClass('active'); 211 | $('#navSignInButton').show(); 212 | $('#navSignUpButton').show(); 213 | $('#navSignOutButton').hide(); 214 | $('#composeTo').val(''); 215 | $('#composeTo').removeClass('invalid'); 216 | $('#composePublicKey').val(''); 217 | $('#composeShowPublicKey').hide(); 218 | $('#composePublicKeyButton').attr('checked', false) 219 | $('.jumbotron').show(); 220 | } 221 | function signOut(davemail){ 222 | davemail.messagesTable.destroy(); 223 | davemail.messagesTable = $('#messagesTable').DataTable({ 224 | data: [], 225 | ordering: false, 226 | columns: [ 227 | {title: "Message"}, 228 | {title: "Time"} 229 | ] 230 | }); 231 | davemail.username = undefined; 232 | davemail.password = undefined; 233 | davemail.passwordStrength = undefined; 234 | davemail.publicKey = undefined; 235 | davemail.privateKey = undefined; 236 | davemail.messages = undefined; 237 | return davemail; 238 | } 239 | function scryptMe(string){ 240 | // Scrypt - https://github.com/tonyg/js-scrypt 241 | var newString = string; 242 | var utf8String = scrypt.encode_utf8(newString); 243 | var utf8Salt = scrypt.encode_utf8('davemail'); 244 | var utf8StringScrypt = scrypt.crypto_scrypt(utf8String, utf8Salt, Math.pow(2, 14), 8, 1, 64); 245 | newString = scrypt.to_hex(utf8StringScrypt); 246 | console.log(newString); 247 | return newString; 248 | } 249 | function generateKeyPair(davemail){ 250 | davemail.privateKey = cryptico.generateRSAKey(scryptMe(davemail.password), 1536); 251 | davemail.publicKey = cryptico.publicKeyString(davemail.privateKey); 252 | console.log(davemail.privateKey); 253 | console.log(davemail.publicKey); 254 | return davemail; 255 | } 256 | function encryptMessage(string, time, key){ 257 | var nonce = scryptMe(time); 258 | var message = cryptico.encrypt(string.concat(nonce), key); 259 | return message; 260 | } 261 | 262 | function mapMessages(davemail){ 263 | davemail.decryptedMessages = new Array(); 264 | return _.map(davemail.jsonData.responseJSON.davemail.emails, function(num, key){ 265 | var message = cryptico.decrypt(num.cipher, davemail.privateKey); 266 | if (message.status == 'success'){ 267 | var timeReadable = moment(num.time).format("MMM Do YY"); 268 | var messageWithoutNonce = message.plaintext.substring(0, (message.plaintext.length) - 128); 269 | davemail.decryptedMessages.push([ messageWithoutNonce, timeReadable ]); 270 | return [ messageWithoutNonce, timeReadable ]; 271 | } 272 | }); 273 | } 274 | 275 | function buildMessagesTable(davemail){ 276 | if (!_.isUndefined(davemail.decryptedMessages[0])){ 277 | davemail.messagesTable.destroy(); 278 | davemail.messagesTable = $('#messagesTable').DataTable({ 279 | data: davemail.decryptedMessages, 280 | ordering: false, 281 | columns: [ 282 | {title: "Message"}, 283 | {title: "Time"} 284 | ] 285 | }); 286 | } 287 | } 288 | 289 | // - Application 290 | 291 | // Load davemail.json 292 | davemail.jsonData = loadDavemail(); 293 | 294 | // Let users upload davemail.json if it fails to load 295 | $(document).on('change', '#importDavemailFile', function(event){ 296 | var reader = new FileReader(); 297 | $('#importDavemailButton').hide(); 298 | $('#importingLoader').show(); 299 | reader.onload = function(event){ 300 | console.log('davemail.json loaded confirmation one'); 301 | var jsonObj = JSON.parse(event.target.result); 302 | davemail.jsonData = new Object(); 303 | davemail.jsonData.responseJSON = jsonObj; 304 | $('nav').show(); 305 | $('#signIn').show(); 306 | $('#importDavemail').hide(); 307 | } 308 | reader.readAsText(event.target.files[0]); 309 | }); 310 | 311 | $('#navSignInButton').click(function(event){ 312 | signInPage(event); 313 | }); 314 | $('#navSignUpButton').click(function(event){ 315 | signUpPage(event); 316 | }); 317 | $('#navMessagesButton').click(function(event){ 318 | messagesPage(event); 319 | }); 320 | $('#navComposeButton').click(function(event){ 321 | composePage(event); 322 | }); 323 | $('#navSignOutButton').click(function(event){ 324 | signOutPage(event); 325 | davemail = signOut(davemail); 326 | }); 327 | $('#signUpButtonOnSignIn').click(function(event){ 328 | signUpPage(event); 329 | }); 330 | 331 | davemail.messagesTable = $('#messagesTable').DataTable({ 332 | data: [], 333 | ordering: false, 334 | columns: [ 335 | {title: "Message"}, 336 | {title: "Time"} 337 | ] 338 | }); 339 | 340 | $('#signInButton').click(function(){ 341 | 342 | $('#signInButton').hide(); 343 | $('#signingInLoader').show(); 344 | 345 | davemail.password = $('#signInPassword').val(); 346 | davemail.passwordStrength = zxcvbn(davemail.password); 347 | 348 | if(davemail.passwordStrength.score < 4){ 349 | setTimeout(function (){ 350 | $('#passwordWarningSignIn').show(); 351 | $('#signInButton').show(); 352 | $('#signingInLoader').hide(); 353 | }, 100); 354 | }else{ 355 | setTimeout(function (){ 356 | davemail = generateKeyPair(davemail); 357 | 358 | _.map(davemail.jsonData.responseJSON.davemail.users, function(num, key){ 359 | if(davemail.publicKey == num.publicKey){ 360 | $('#usernameHeading').text(key); 361 | davemail.username = key; 362 | } 363 | }); 364 | 365 | $('#signingInLoader').hide(); 366 | $('#signIn').hide(); 367 | $('#signInPassword').val(''); 368 | 369 | messagesPage(); 370 | davemail.messages = mapMessages(davemail); 371 | buildMessagesTable(davemail); 372 | composeInit(davemail); 373 | 374 | }, 10); 375 | } 376 | }); 377 | 378 | $('#signUpButton').click(function(){ 379 | 380 | $('#signUpUsername').val($('#signUpUsername').val().toLowerCase()); 381 | davemail.username = $('#signUpUsername').val(); 382 | davemail.password = $('#signUpPassword').val(); 383 | davemail.passwordStrength = zxcvbn(davemail.password); 384 | 385 | $('#usernameTakenWarning').hide(); 386 | $('#passwordWarning').hide(); 387 | 388 | if(davemail.username.length > 0){ 389 | $('#usernameEmptyWarning').hide(); 390 | 391 | // TODO: Simplify this logic 392 | var usernameTaken = _.map(davemail.jsonData.responseJSON.davemail.users, function(num, key){ 393 | if(davemail.username == key.toLowerCase()){ 394 | return true; 395 | }else{ 396 | return false; 397 | } 398 | }); 399 | 400 | if(_.contains(usernameTaken, true)){ 401 | $('#usernameTakenWarning').show(); 402 | $('#passwordWarning').hide(); 403 | usernameTaken = true; 404 | }else{ 405 | usernameTaken = false; 406 | } 407 | 408 | var usernameLegal = /^[a-z0-9]*$/.test(davemail.username); 409 | 410 | if(!usernameLegal){ 411 | $('#usernameIllegalWarning').show(); 412 | }else{ 413 | $('#usernameIllegalWarning').hide(); 414 | } 415 | 416 | if(usernameLegal && (!usernameTaken) && davemail.passwordStrength.score > 3){ 417 | $('#passwordWarning').hide(); 418 | $('#signUpButton').hide(); 419 | $('#signingUpLoader').show(); 420 | 421 | setTimeout(function (){ 422 | davemail = generateKeyPair(davemail); 423 | 424 | // Regenerate users json 425 | var users = davemail.jsonData.responseJSON.davemail.users; 426 | var emails = davemail.jsonData.responseJSON.davemail.emails; 427 | var servers = davemail.jsonData.responseJSON.davemail.servers; 428 | users[davemail.username] = {'publicKey': davemail.publicKey}; // Add user to users 429 | 430 | davemail.jsonData.responseJSON = {'davemail': {'users': users, 'emails': emails, 'servers': servers}}; // Replace local json 431 | $('#signUpJson').text(JSON.stringify(davemail.jsonData.responseJSON, null, 4)); 432 | 433 | var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(davemail.jsonData.responseJSON, null, 4)); 434 | $('#signUpUsername').val(''); 435 | $('#signUpPassword').val(''); 436 | $('#signUp').hide(); 437 | $('#signUpReplace').show(); 438 | $('Right click here').appendTo('#signUpDownload'); 439 | 440 | composeInit(davemail); 441 | 442 | }, 100); 443 | 444 | }else{ 445 | if(davemail.passwordStrength.score < 4){ 446 | $('#passwordWarning').show(); 447 | } 448 | $('#passwordWarningText').text(davemail.passwordStrength.feedback.warning); 449 | var passwordSuggestions = $('#passwordSuggestionsText'); 450 | passwordSuggestions.children().remove(); 451 | $.each(davemail.passwordStrength.feedback.suggestions, function(i){ 452 | var p = $('

    ') 453 | .appendTo(passwordSuggestions) 454 | .text(davemail.passwordStrength.feedback.suggestions[i]) 455 | .appendTo(p); 456 | }); 457 | } 458 | }else{ 459 | $('#usernameEmptyWarning').show(); 460 | } 461 | }); 462 | 463 | $('#composeSendButton').click(function(){ 464 | if(davemail.jsonData.responseJSON.davemail.users[$('#composeTo').val()].publicKey == $('#composePublicKey').val()){ 465 | $(this).hide(); 466 | $('#sendingLoader').show(); 467 | var date = new Date(); 468 | var message = encryptMessage($('#composeMessage').val(), date.toISOString(), $('#composePublicKey').val()); 469 | console.log(message); 470 | if(message.status == 'success'){ 471 | setTimeout(function (){ 472 | $('#composeTo').val(''); 473 | $('#composePublicKey').val(''); 474 | $('#composeMessage').val(''); 475 | $('#sendingLoader').hide(); 476 | $('#compose').hide(); 477 | $('#signUpReplace').show(); 478 | 479 | // Regenerate emails json 480 | var users = davemail.jsonData.responseJSON.davemail.users; 481 | var emails = davemail.jsonData.responseJSON.davemail.emails; 482 | var servers = davemail.jsonData.responseJSON.davemail.servers; 483 | emails.push({'time': date.toISOString(), 'cipher': message.cipher}); // Add user to users 484 | 485 | davemail.jsonData.responseJSON = {'davemail': {'users': users, 'emails': emails, 'servers': servers}}; // Replace local json 486 | $('#signUpJson').text(JSON.stringify(davemail.jsonData.responseJSON, null, 4)); 487 | 488 | var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(davemail.jsonData.responseJSON, null, 4)); 489 | $('Right click here').appendTo('#signUpDownload'); 490 | 491 | }, 100); 492 | } 493 | }else{ 494 | console.log('fail'); 495 | } 496 | }); 497 | 498 | $('#fileReplacedButton').click(function(){ 499 | $('#fileReplacedButton').hide(); 500 | $('#fileReplacedLoader').show(); 501 | setTimeout(function (){ 502 | loadDavemailAgain(davemail); 503 | }, 500); 504 | }); 505 | 506 | })(); 507 | -------------------------------------------------------------------------------- /app/styles/davemail/style.scss: -------------------------------------------------------------------------------- 1 | .jumbotron { 2 | color:#ffffff; 3 | background-color: #2c3b63; 4 | img { 5 | max-height: 160px; 6 | } 7 | p { 8 | font-size: 14px; 9 | } 10 | } 11 | .btn-primary { 12 | border-color: #2c3b63; 13 | background-color: #2c3b63; 14 | } 15 | #messagesTable_wrapper { 16 | margin-top: 40px; 17 | margin-bottom: 40px; 18 | thead { 19 | display: none; 20 | } 21 | td:first-child { 22 | width: 85%; 23 | } 24 | } 25 | 26 | .davemail-messages-table { 27 | width: 100% !important; 28 | } 29 | .davemail-sign-up-username { 30 | text-transform: lowercase; 31 | } 32 | .inline-block { 33 | display: inline-block !important; 34 | } 35 | .compose-users-list-wrapper { 36 | top: -1px; 37 | position: relative; 38 | } 39 | .compose-users-list { 40 | position: absolute; 41 | width: 100%; 42 | border: 1px solid #cccccc; 43 | background-color: #ffffff; 44 | box-shadow: 0 2px 4px rgba(0,0,0,0.2); 45 | -webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.2); 46 | li { 47 | padding: 1px 12px; 48 | list-style-type: none; 49 | &:hover { 50 | background-color: #eeeeee; 51 | } 52 | } 53 | } 54 | .show-public-key { 55 | color: #999999; 56 | } 57 | .invalid { 58 | border-color: #fd6e8a; 59 | } -------------------------------------------------------------------------------- /app/styles/main.scss: -------------------------------------------------------------------------------- 1 | $icon-font-path: '../fonts/'; 2 | 3 | // bower:scss 4 | @import "bower_components/bootstrap-sass/assets/stylesheets/_bootstrap.scss"; 5 | @import "bower_components/font-awesome/scss/font-awesome.scss"; 6 | @import "bower_components/tailor/sass/tailor.scss"; 7 | @import "app/styles/davemail/style.scss"; 8 | @import "bower_components/nudge/sass/nudge.scss"; 9 | // endbower -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "davemail", 3 | "version": "2.0.0", 4 | "private": false, 5 | "dependencies": { 6 | "bootstrap-sass": "~3.3.5", 7 | "modernizr": "~2.8.1", 8 | "nudge": "^1.2.3", 9 | "font-awesome": "^4.5.0", 10 | "datatables": "^1.10.11", 11 | "underscore": "^1.8.3", 12 | "js-scrypt": "git://github.com/tonyg/js-scrypt.git#1427dcb6f58385fb83aafeb6d5ec05b3d1d72ec2", 13 | "cryptico": "git://github.com/wwwtyro/cryptico.git#9291ece634d37415e66396d749d38e612d66f935", 14 | "zxcvbn": "^4.3.0", 15 | "jquery.listfilter": "^1.0.10", 16 | "tailor": "git://github.com/davidapple/tailor", 17 | "moment": "^2.13.0" 18 | }, 19 | "overrides": { 20 | "bootstrap-sass": { 21 | "main": [ 22 | "assets/stylesheets/_bootstrap.scss", 23 | "assets/fonts/bootstrap/*", 24 | "assets/javascripts/bootstrap.js" 25 | ] 26 | } 27 | }, 28 | "devDependencies": { 29 | "chai": "^3.5.0", 30 | "mocha": "^2.4.5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dist/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/apple-touch-icon.png -------------------------------------------------------------------------------- /dist/davemail.json: -------------------------------------------------------------------------------- 1 | { 2 | "davemail": { 3 | "users": { 4 | "tinyi": { 5 | "publicKey": "Waa5H1sVsFmPuDqSZFKMPOgPSmhUQMtcoIaQA87iryXJVH3jhYueW+qIBBOo2x2JNzd05Pm3gJqrFHnFXnJA5UfNIIQlWn6wbxnfced/JRcE2fS0FmrLH+XDB6xms5/ZX+ZzGRKNTOJtk/WNhJSSQsYWa3DbkqZgLMw4m3go9gVeSYN0Isjo2hhQ3fKeW+MrAoaynyRHA6s5OB4I5E/Af71TeqmsLNGl4dlcqYa+ameh6e/PiiKJw6x3SWJJAbYn" 6 | }, 7 | "davidapple": { 8 | "publicKey": "TCQy+rIxLzvd0MDap6CT0ZTxZnKQiT9bNyRzr63Ob77Yxe3zUkGNR/qDxhMMNVgZjvFDEA+Z5lnMx+YHCdLni3pN4Ssj4waS+VuixBHRxU90PFLy/pWK08rOf5pEicCStdSQbfe7MQupQN3CUnBCK9gzG7H8RoVBP3pzy4yAv1us7GC+7+urMfxdz1YoZwGOK99okhcXGnb49w2I9B1Aj0qwjVLMTlRypdgikVCEBwLthcbTSSekCDBSyv/296zF" 9 | } 10 | }, 11 | "emails": [ 12 | { 13 | "time": "2016-05-05T11:14:51.446Z", 14 | "cipher": "Gp4xk6E6NFpm48nHWRHOx1qVRdOtgdZ/lKHBcu8IYA5bFvwf+tUrhNNy+YjyjGRZ8amDubTJzrT+PMFlNm/gbIwho5SbSozMS5qAszscHfXOr3vT2S9NJsbAjm+D8/RdmJI0ZA7omP7ENEBH6VBHMWoDMGfJ/685ic63Bah/wEKBWMk6oL2NtWNVwEiDtwxta72US0oBodzWzKfDSbe+HTuwzcgqL8Grt7YGMsPeZgqO/xyMc9BXcqAGDjY+YLVT?TR2VnwLHpi6j0ofBrFRagI4oEoBczrYnXpaVTfNpRu+NuSnr7vr4ClWpyqWczHi1FzGXzDWFacLVapbaOhYEX142TQCVknCseUCekMWx7bjeRx/8EmN62JVwCRQjq2EE/qKIaxjK7CIByQ+sQPCRmndSzS6D6FUqgRNrNuEgLZAAjWoZbdgEX6vg0P9cHXJ9dznoka3R2sjKiPSPCJRajAqH2eQbEMNGFe5GyfCAxqUx34ryzALYFXq3ZN8wLN0Vx/Ou98mCu0Kqp1XJBWL6qg==" 15 | } 16 | ], 17 | "servers": [ 18 | { 19 | "ssh": "git@github.com:davidapple/davemail.git", 20 | "username": "anonymous", 21 | "password": "example", 22 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4LojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4kYjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9EzSdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myivO7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPqdAv8JggJICUvax2T9va5 gsg-keypair" 23 | } 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/favicon.ico -------------------------------------------------------------------------------- /dist/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /dist/images/davemail-login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/davemail-login.jpg -------------------------------------------------------------------------------- /dist/images/davemail-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/davemail-logo.png -------------------------------------------------------------------------------- /dist/images/davemail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/davemail.png -------------------------------------------------------------------------------- /dist/images/noise/noise-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/noise/noise-loud.png -------------------------------------------------------------------------------- /dist/images/noise/noise-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/noise/noise-soft.png -------------------------------------------------------------------------------- /dist/images/noise/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/noise/noise.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley-lg-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley-lg-100.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley-lg-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley-lg-loud.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley-lg-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley-lg-soft.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley-lg.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley-loud.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley-soft.png -------------------------------------------------------------------------------- /dist/images/paisley/paisley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/paisley/paisley.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-lg-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-lg-loud.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-lg-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-lg-soft.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-lg-xloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-lg-xloud.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-lg.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-loud.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-md-xloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-md-xloud.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-sm-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-sm-loud.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-sm-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-sm-soft.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-sm-xloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-sm-xloud.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-sm.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe-soft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe-soft.png -------------------------------------------------------------------------------- /dist/images/pinstripe/pinstripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidapple/davemail/0e922739ae73e7630c8166f85565f77215fb06a0/dist/images/pinstripe/pinstripe.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | Davemail

    Davemail

    Decentralised, deterministic RSA encrypted, anonymous, offline email for git.

    Sign In

    Under the hood

    The sign in button generates a RSA key pair on your local machine (see browser console).

    -------------------------------------------------------------------------------- /dist/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /dist/scripts/main.js: -------------------------------------------------------------------------------- 1 | "use strict";!function(){function e(){return $.getJSON("davemail.json",function(){console.log("davemail.json loaded confirmation one")}).done(function(){console.log("davemail.json loaded confirmation two")}).fail(function(e,a,n){var o=a+", "+n;console.log("davemail.json failed to load: "+o),s()})}function a(e){$.getJSON("davemail.json",function(){console.log("davemail.json loaded confirmation one")}).done(function(a){console.log("davemail.json loaded confirmation two"),_.isEqual(e.jsonData.responseJSON,a)?($("#signUpReplaceDownload").remove(),$("#signUpButton").show(),$("#signingUpLoader").hide(),$("#fileReplacedButton").show(),$("#fileReplacedLoader").hide(),$("#usernameHeading").text(e.username),t(),e.messages=v(e),u(e)):($("#fileNotReplacedWarning").show(),$("#fileReplacedLoader").hide(),$("#fileReplacedButton").show())}).fail(function(a,n,s){var o=n+", "+s;console.log("davemail.json failed to load: "+o),$("#signUpReplaceDownload").remove(),$("#signUpButton").show(),$("#signingUpLoader").hide(),$("#fileReplacedButton").show(),$("#fileReplacedLoader").hide(),$("#usernameHeading").text(e.username),t(),e.messages=v(e),u(e)})}function n(e){$("#composeToList li").remove();var a=_.map(e.jsonData.responseJSON.davemail.users,function(e,a){return $("
  • ").text(a).click(function(n){$("#composeTo").val(a),$("#composeTo").removeClass("invalid"),$("#composePublicKey").val(e.publicKey),$("#composeToListWrapper").hide(),$("#composeSendButton").show()}).appendTo("#composeToList"),a}),n=$("#composeTo"),s=$("input#clearfilter");$("#composeToList").listfilter({filter:n,clearlink:s,alternate:!0,alternateclass:"other"}),$("#composeTo").keyup(function(){$("#composeTo").val().length>0?($("#composeToListWrapper").show(),0==$("#composeToList li:visible").length&&$("#composeToListWrapper").hide(),-1==_.indexOf(a,$("#composeTo").val())?($("#composePublicKey").val(""),$("#composeSendButton").hide()):($("#composePublicKey").val(e.jsonData.responseJSON.davemail.users[$("#composeTo").val()].publicKey),$("#composeSendButton").show())):$("#composeToListWrapper").hide()}).focusout(function(){setTimeout(function(){-1==_.indexOf(a,$("#composeTo").val())?$("#composeTo").addClass("invalid"):($("#composeTo").removeClass("invalid"),$("#composeToListWrapper").hide())},10)}),$("#composePublicKeyButton").click(function(){$(this).prop("checked")?$("#composeShowPublicKey").show():$("#composeShowPublicKey").hide()})}function s(e){_.isObject(e)&&e.preventDefault(),$("#importDavemail").show(),$("nav").hide(),$("#signIn").hide(),$("#signUp").hide(),$("#messages").hide(),$("#signUpReplace").hide(),$("#navSignInButton").parent().removeClass("active"),$("#navSignUpButton").parent().removeClass("active"),$("#navMessagesButton").parent().removeClass("active")}function o(e){_.isObject(e)&&e.preventDefault(),$("#signIn").show(),$("#signUp").hide(),$("#messages").hide(),$("#signUpReplace").hide(),$("#navSignInButton").parent().addClass("active"),$("#navSignUpButton").parent().removeClass("active"),$("#navMessagesButton").parent().removeClass("active")}function i(e){_.isObject(e)&&e.preventDefault(),$("#signUp").show(),$("#signIn").hide(),$("#messages").hide(),$("#navSignUpButton").parent().addClass("active"),$("#navSignInButton").parent().removeClass("active"),$("#navMessagesButton").parent().removeClass("active")}function t(e){_.isObject(e)&&e.preventDefault(),$("#messages").show(),$("#compose").hide(),$("#signIn").hide(),$("#signUp").hide(),$("#signUpReplace").hide(),$("#navMessagesButton").show(),$("#navMessagesButton").parent().addClass("active"),$("#navComposeButton").show(),$("#navComposeButton").parent().removeClass("active"),$("#navSignInButton").parent().removeClass("active"),$("#navSignUpButton").parent().removeClass("active"),$("#navSignOutButton").show(),$("#navSignInButton").hide(),$("#navSignUpButton").hide(),$(".jumbotron").hide()}function l(e){_.isObject(e)&&e.preventDefault(),$("#messages").hide(),$("#compose").show(),$("#signIn").hide(),$("#signUp").hide(),$("#signUpReplace").hide(),$("#navMessagesButton").show(),$("#navMessagesButton").parent().removeClass("active"),$("#navComposeButton").show(),$("#navComposeButton").parent().addClass("active"),$("#navSignInButton").parent().removeClass("active"),$("#navSignUpButton").parent().removeClass("active"),$("#navSignOutButton").show(),$("#navSignInButton").hide(),$("#navSignUpButton").hide(),$(".jumbotron").hide()}function r(e){_.isObject(e)&&e.preventDefault(),$("#signIn").show(),$("#signInButton").show(),$("#messages").hide(),$("#compose").hide(),$("#signUp").hide(),$("#signUpReplace").hide(),$("#navComposeButton").hide(),$("#navMessagesButton").hide(),$("#navSignInButton").parent().addClass("active"),$("#navComposeButton").parent().removeClass("active"),$("#navMessagesButton").parent().removeClass("active"),$("#navSignUpButton").parent().removeClass("active"),$("#navSignInButton").show(),$("#navSignUpButton").show(),$("#navSignOutButton").hide(),$("#composeTo").val(""),$("#composeTo").removeClass("invalid"),$("#composePublicKey").val(""),$("#composeShowPublicKey").hide(),$("#composePublicKeyButton").attr("checked",!1),$(".jumbotron").show()}function d(e){return e.messagesTable.destroy(),e.messagesTable=$("#messagesTable").DataTable({data:[],ordering:!1,columns:[{title:"Message"},{title:"Time"}]}),e.username=void 0,e.password=void 0,e.passwordStrength=void 0,e.publicKey=void 0,e.privateKey=void 0,e.messages=void 0,e}function c(e){var a=e,n=g.encode_utf8(a),s=g.encode_utf8("davemail"),o=g.crypto_scrypt(n,s,Math.pow(2,14),8,1,64);return a=g.to_hex(o),console.log(a),a}function p(e){return e.privateKey=cryptico.generateRSAKey(c(e.password),1536),e.publicKey=cryptico.publicKeyString(e.privateKey),console.log(e.privateKey),console.log(e.publicKey),e}function m(e,a,n){var s=c(a),o=cryptico.encrypt(e.concat(s),n);return o}function v(e){return e.decryptedMessages=new Array,_.map(e.jsonData.responseJSON.davemail.emails,function(a,n){var s=cryptico.decrypt(a.cipher,e.privateKey);if("success"==s.status){var o=moment(a.time).format("MMM Do YY"),i=s.plaintext.substring(0,s.plaintext.length-128);return e.decryptedMessages.push([i,o]),[i,o]}})}function u(e){_.isUndefined(e.decryptedMessages[0])||(e.messagesTable.destroy(),e.messagesTable=$("#messagesTable").DataTable({data:e.decryptedMessages,ordering:!1,columns:[{title:"Message"},{title:"Time"}]}))}window.davemail=new Object,davemail.info="Davemail 2.0.0 by David Apple https://github.com/davidapple/davemail Donate Bitcoin to 13D3A8PP91MLF5VTBQMH5HG76F42RNRF28";var g=scrypt_module_factory();davemail.jsonData=e(),$(document).on("change","#importDavemailFile",function(e){var a=new FileReader;$("#importDavemailButton").hide(),$("#importingLoader").show(),a.onload=function(e){console.log("davemail.json loaded confirmation one");var a=JSON.parse(e.target.result);davemail.jsonData=new Object,davemail.jsonData.responseJSON=a,$("nav").show(),$("#signIn").show(),$("#importDavemail").hide()},a.readAsText(e.target.files[0])}),$("#navSignInButton").click(function(e){o(e)}),$("#navSignUpButton").click(function(e){i(e)}),$("#navMessagesButton").click(function(e){t(e)}),$("#navComposeButton").click(function(e){l(e)}),$("#navSignOutButton").click(function(e){r(e),davemail=d(davemail)}),$("#signUpButtonOnSignIn").click(function(e){i(e)}),davemail.messagesTable=$("#messagesTable").DataTable({data:[],ordering:!1,columns:[{title:"Message"},{title:"Time"}]}),$("#signInButton").click(function(){$("#signInButton").hide(),$("#signingInLoader").show(),davemail.password=$("#signInPassword").val(),davemail.passwordStrength=zxcvbn(davemail.password),davemail.passwordStrength.score<4?setTimeout(function(){$("#passwordWarningSignIn").show(),$("#signInButton").show(),$("#signingInLoader").hide()},100):setTimeout(function(){davemail=p(davemail),_.map(davemail.jsonData.responseJSON.davemail.users,function(e,a){davemail.publicKey==e.publicKey&&($("#usernameHeading").text(a),davemail.username=a)}),$("#signingInLoader").hide(),$("#signIn").hide(),$("#signInPassword").val(""),t(),davemail.messages=v(davemail),u(davemail),n(davemail)},10)}),$("#signUpButton").click(function(){if($("#signUpUsername").val($("#signUpUsername").val().toLowerCase()),davemail.username=$("#signUpUsername").val(),davemail.password=$("#signUpPassword").val(),davemail.passwordStrength=zxcvbn(davemail.password),$("#usernameTakenWarning").hide(),$("#passwordWarning").hide(),davemail.username.length>0){$("#usernameEmptyWarning").hide();var e=_.map(davemail.jsonData.responseJSON.davemail.users,function(e,a){return davemail.username==a.toLowerCase()});_.contains(e,!0)?($("#usernameTakenWarning").show(),$("#passwordWarning").hide(),e=!0):e=!1;var a=/^[a-z0-9]*$/.test(davemail.username);if(a?$("#usernameIllegalWarning").hide():$("#usernameIllegalWarning").show(),a&&!e&&davemail.passwordStrength.score>3)$("#passwordWarning").hide(),$("#signUpButton").hide(),$("#signingUpLoader").show(),setTimeout(function(){davemail=p(davemail);var e=davemail.jsonData.responseJSON.davemail.users,a=davemail.jsonData.responseJSON.davemail.emails,s=davemail.jsonData.responseJSON.davemail.servers;e[davemail.username]={publicKey:davemail.publicKey},davemail.jsonData.responseJSON={davemail:{users:e,emails:a,servers:s}},$("#signUpJson").text(JSON.stringify(davemail.jsonData.responseJSON,null,4));var o="text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(davemail.jsonData.responseJSON,null,4));$("#signUpUsername").val(""),$("#signUpPassword").val(""),$("#signUp").hide(),$("#signUpReplace").show(),$('Right click here').appendTo("#signUpDownload"),n(davemail)},100);else{davemail.passwordStrength.score<4&&$("#passwordWarning").show(),$("#passwordWarningText").text(davemail.passwordStrength.feedback.warning);var s=$("#passwordSuggestionsText");s.children().remove(),$.each(davemail.passwordStrength.feedback.suggestions,function(e){var a=$("

    ").appendTo(s).text(davemail.passwordStrength.feedback.suggestions[e]).appendTo(a)})}}else $("#usernameEmptyWarning").show()}),$("#composeSendButton").click(function(){if(davemail.jsonData.responseJSON.davemail.users[$("#composeTo").val()].publicKey==$("#composePublicKey").val()){$(this).hide(),$("#sendingLoader").show();var e=new Date,a=m($("#composeMessage").val(),e.toISOString(),$("#composePublicKey").val());console.log(a),"success"==a.status&&setTimeout(function(){$("#composeTo").val(""),$("#composePublicKey").val(""),$("#composeMessage").val(""),$("#sendingLoader").hide(),$("#compose").hide(),$("#signUpReplace").show();var n=davemail.jsonData.responseJSON.davemail.users,s=davemail.jsonData.responseJSON.davemail.emails,o=davemail.jsonData.responseJSON.davemail.servers;s.push({time:e.toISOString(),cipher:a.cipher}),davemail.jsonData.responseJSON={davemail:{users:n,emails:s,servers:o}},$("#signUpJson").text(JSON.stringify(davemail.jsonData.responseJSON,null,4));var i="text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(davemail.jsonData.responseJSON,null,4));$('Right click here').appendTo("#signUpDownload")},100)}else console.log("fail")}),$("#fileReplacedButton").click(function(){$("#fileReplacedButton").hide(),$("#fileReplacedLoader").show(),setTimeout(function(){a(davemail)},500)})}(); -------------------------------------------------------------------------------- /dist/scripts/plugins.js: -------------------------------------------------------------------------------- 1 | +function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.affix"),s="object"==typeof e&&e;n||o.data("bs.affix",n=new i(this,s)),"string"==typeof e&&n[e]()})}var i=function(e,o){this.options=t.extend({},i.DEFAULTS,o),this.$target=t(this.options.target).on("scroll.bs.affix.data-api",t.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",t.proxy(this.checkPositionWithEventLoop,this)),this.$element=t(e),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};i.VERSION="3.3.6",i.RESET="affix affix-top affix-bottom",i.DEFAULTS={offset:0,target:window},i.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return i>n?"top":!1;if("bottom"==this.affixed)return null!=i?n+this.unpin<=s.top?!1:"bottom":t-o>=n+a?!1:"bottom";var r=null==this.affixed,l=r?n:s.top,h=r?a:e;return null!=i&&i>=n?"top":null!=o&&l+h>=t-o?"bottom":!1},i.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(i.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},i.prototype.checkPositionWithEventLoop=function(){setTimeout(t.proxy(this.checkPosition,this),1)},i.prototype.checkPosition=function(){if(this.$element.is(":visible")){var e=this.$element.height(),o=this.options.offset,n=o.top,s=o.bottom,a=Math.max(t(document).height(),t(document.body).height());"object"!=typeof o&&(s=n=o),"function"==typeof n&&(n=o.top(this.$element)),"function"==typeof s&&(s=o.bottom(this.$element));var r=this.getState(a,e,n,s);if(this.affixed!=r){null!=this.unpin&&this.$element.css("top","");var l="affix"+(r?"-"+r:""),h=t.Event(l+".bs.affix");if(this.$element.trigger(h),h.isDefaultPrevented())return;this.affixed=r,this.unpin="bottom"==r?this.getPinnedOffset():null,this.$element.removeClass(i.RESET).addClass(l).trigger(l.replace("affix","affixed")+".bs.affix")}"bottom"==r&&this.$element.offset({top:a-e-s})}};var o=t.fn.affix;t.fn.affix=e,t.fn.affix.Constructor=i,t.fn.affix.noConflict=function(){return t.fn.affix=o,this},t(window).on("load",function(){t('[data-spy="affix"]').each(function(){var i=t(this),o=i.data();o.offset=o.offset||{},null!=o.offsetBottom&&(o.offset.bottom=o.offsetBottom),null!=o.offsetTop&&(o.offset.top=o.offsetTop),e.call(i,o)})})}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var i=t(this),n=i.data("bs.alert");n||i.data("bs.alert",n=new o(this)),"string"==typeof e&&n[e].call(i)})}var i='[data-dismiss="alert"]',o=function(e){t(e).on("click",i,this.close)};o.VERSION="3.3.6",o.TRANSITION_DURATION=150,o.prototype.close=function(e){function i(){a.detach().trigger("closed.bs.alert").remove()}var n=t(this),s=n.attr("data-target");s||(s=n.attr("href"),s=s&&s.replace(/.*(?=#[^\s]*$)/,""));var a=t(s);e&&e.preventDefault(),a.length||(a=n.closest(".alert")),a.trigger(e=t.Event("close.bs.alert")),e.isDefaultPrevented()||(a.removeClass("in"),t.support.transition&&a.hasClass("fade")?a.one("bsTransitionEnd",i).emulateTransitionEnd(o.TRANSITION_DURATION):i())};var n=t.fn.alert;t.fn.alert=e,t.fn.alert.Constructor=o,t.fn.alert.noConflict=function(){return t.fn.alert=n,this},t(document).on("click.bs.alert.data-api",i,o.prototype.close)}(jQuery),+function(t){"use strict";function e(e){var i=e.attr("data-target");i||(i=e.attr("href"),i=i&&/#[A-Za-z]/.test(i)&&i.replace(/.*(?=#[^\s]*$)/,""));var o=i&&t(i);return o&&o.length?o:e.parent()}function i(i){i&&3===i.which||(t(n).remove(),t(s).each(function(){var o=t(this),n=e(o),s={relatedTarget:this};n.hasClass("open")&&(i&&"click"==i.type&&/input|textarea/i.test(i.target.tagName)&&t.contains(n[0],i.target)||(n.trigger(i=t.Event("hide.bs.dropdown",s)),i.isDefaultPrevented()||(o.attr("aria-expanded","false"),n.removeClass("open").trigger(t.Event("hidden.bs.dropdown",s)))))}))}function o(e){return this.each(function(){var i=t(this),o=i.data("bs.dropdown");o||i.data("bs.dropdown",o=new a(this)),"string"==typeof e&&o[e].call(i)})}var n=".dropdown-backdrop",s='[data-toggle="dropdown"]',a=function(e){t(e).on("click.bs.dropdown",this.toggle)};a.VERSION="3.3.6",a.prototype.toggle=function(o){var n=t(this);if(!n.is(".disabled, :disabled")){var s=e(n),a=s.hasClass("open");if(i(),!a){"ontouchstart"in document.documentElement&&!s.closest(".navbar-nav").length&&t(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(t(this)).on("click",i);var r={relatedTarget:this};if(s.trigger(o=t.Event("show.bs.dropdown",r)),o.isDefaultPrevented())return;n.trigger("focus").attr("aria-expanded","true"),s.toggleClass("open").trigger(t.Event("shown.bs.dropdown",r))}return!1}},a.prototype.keydown=function(i){if(/(38|40|27|32)/.test(i.which)&&!/input|textarea/i.test(i.target.tagName)){var o=t(this);if(i.preventDefault(),i.stopPropagation(),!o.is(".disabled, :disabled")){var n=e(o),a=n.hasClass("open");if(!a&&27!=i.which||a&&27==i.which)return 27==i.which&&n.find(s).trigger("focus"),o.trigger("click");var r=" li:not(.disabled):visible a",l=n.find(".dropdown-menu"+r);if(l.length){var h=l.index(i.target);38==i.which&&h>0&&h--,40==i.which&&h

    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},i.prototype.init=function(e,i,o){if(this.enabled=!0,this.type=e,this.$element=t(i),this.options=this.getOptions(o),this.$viewport=this.options.viewport&&t(t.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var n=this.options.trigger.split(" "),s=n.length;s--;){var a=n[s];if("click"==a)this.$element.on("click."+this.type,this.options.selector,t.proxy(this.toggle,this));else if("manual"!=a){var r="hover"==a?"mouseenter":"focusin",l="hover"==a?"mouseleave":"focusout";this.$element.on(r+"."+this.type,this.options.selector,t.proxy(this.enter,this)),this.$element.on(l+"."+this.type,this.options.selector,t.proxy(this.leave,this))}}this.options.selector?this._options=t.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},i.prototype.getDefaults=function(){return i.DEFAULTS},i.prototype.getOptions=function(e){return e=t.extend({},this.getDefaults(),this.$element.data(),e),e.delay&&"number"==typeof e.delay&&(e.delay={show:e.delay,hide:e.delay}),e},i.prototype.getDelegateOptions=function(){var e={},i=this.getDefaults();return this._options&&t.each(this._options,function(t,o){i[t]!=o&&(e[t]=o)}),e},i.prototype.enter=function(e){var i=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i)),e instanceof t.Event&&(i.inState["focusin"==e.type?"focus":"hover"]=!0),i.tip().hasClass("in")||"in"==i.hoverState?void(i.hoverState="in"):(clearTimeout(i.timeout),i.hoverState="in",i.options.delay&&i.options.delay.show?void(i.timeout=setTimeout(function(){"in"==i.hoverState&&i.show()},i.options.delay.show)):i.show())},i.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},i.prototype.leave=function(e){var i=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i)),e instanceof t.Event&&(i.inState["focusout"==e.type?"focus":"hover"]=!1),i.isInStateTrue()?void 0:(clearTimeout(i.timeout),i.hoverState="out",i.options.delay&&i.options.delay.hide?void(i.timeout=setTimeout(function(){"out"==i.hoverState&&i.hide()},i.options.delay.hide)):i.hide())},i.prototype.show=function(){var e=t.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var o=t.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!o)return;var n=this,s=this.tip(),a=this.getUID(this.type);this.setContent(),s.attr("id",a),this.$element.attr("aria-describedby",a),this.options.animation&&s.addClass("fade");var r="function"==typeof this.options.placement?this.options.placement.call(this,s[0],this.$element[0]):this.options.placement,l=/\s?auto?\s?/i,h=l.test(r);h&&(r=r.replace(l,"")||"top"),s.detach().css({top:0,left:0,display:"block"}).addClass(r).data("bs."+this.type,this),this.options.container?s.appendTo(this.options.container):s.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var d=this.getPosition(),p=s[0].offsetWidth,c=s[0].offsetHeight;if(h){var f=r,u=this.getPosition(this.$viewport);r="bottom"==r&&d.bottom+c>u.bottom?"top":"top"==r&&d.top-cu.width?"left":"left"==r&&d.left-pa.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;ha.right&&(n.left=a.left+a.width-d)}return n},i.prototype.getTitle=function(){var t,e=this.$element,i=this.options;return t=e.attr("data-original-title")||("function"==typeof i.title?i.title.call(e[0]):i.title)},i.prototype.getUID=function(t){do t+=~~(1e6*Math.random());while(document.getElementById(t));return t},i.prototype.tip=function(){if(!this.$tip&&(this.$tip=t(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},i.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},i.prototype.enable=function(){this.enabled=!0},i.prototype.disable=function(){this.enabled=!1},i.prototype.toggleEnabled=function(){this.enabled=!this.enabled},i.prototype.toggle=function(e){var i=this;e&&(i=t(e.currentTarget).data("bs."+this.type),i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i))),e?(i.inState.click=!i.inState.click,i.isInStateTrue()?i.enter(i):i.leave(i)):i.tip().hasClass("in")?i.leave(i):i.enter(i)},i.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null})};var o=t.fn.tooltip;t.fn.tooltip=e,t.fn.tooltip.Constructor=i,t.fn.tooltip.noConflict=function(){return t.fn.tooltip=o,this}}(jQuery),+function(t){"use strict";function e(e,o){return this.each(function(){var n=t(this),s=n.data("bs.modal"),a=t.extend({},i.DEFAULTS,n.data(),"object"==typeof e&&e);s||n.data("bs.modal",s=new i(this,a)),"string"==typeof e?s[e](o):a.show&&s.show(o)})}var i=function(e,i){this.options=i,this.$body=t(document.body),this.$element=t(e),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,t.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};i.VERSION="3.3.6",i.TRANSITION_DURATION=300,i.BACKDROP_TRANSITION_DURATION=150,i.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},i.prototype.toggle=function(t){return this.isShown?this.hide():this.show(t)},i.prototype.show=function(e){var o=this,n=t.Event("show.bs.modal",{relatedTarget:e});this.$element.trigger(n),this.isShown||n.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',t.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){o.$element.one("mouseup.dismiss.bs.modal",function(e){t(e.target).is(o.$element)&&(o.ignoreBackdropClick=!0)})}),this.backdrop(function(){var n=t.support.transition&&o.$element.hasClass("fade");o.$element.parent().length||o.$element.appendTo(o.$body),o.$element.show().scrollTop(0),o.adjustDialog(),n&&o.$element[0].offsetWidth,o.$element.addClass("in"),o.enforceFocus();var s=t.Event("shown.bs.modal",{relatedTarget:e});n?o.$dialog.one("bsTransitionEnd",function(){o.$element.trigger("focus").trigger(s)}).emulateTransitionEnd(i.TRANSITION_DURATION):o.$element.trigger("focus").trigger(s)}))},i.prototype.hide=function(e){e&&e.preventDefault(),e=t.Event("hide.bs.modal"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),t(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),t.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",t.proxy(this.hideModal,this)).emulateTransitionEnd(i.TRANSITION_DURATION):this.hideModal())},i.prototype.enforceFocus=function(){t(document).off("focusin.bs.modal").on("focusin.bs.modal",t.proxy(function(t){this.$element[0]===t.target||this.$element.has(t.target).length||this.$element.trigger("focus")},this))},i.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",t.proxy(function(t){27==t.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},i.prototype.resize=function(){this.isShown?t(window).on("resize.bs.modal",t.proxy(this.handleUpdate,this)):t(window).off("resize.bs.modal")},i.prototype.hideModal=function(){var t=this;this.$element.hide(),this.backdrop(function(){t.$body.removeClass("modal-open"),t.resetAdjustments(),t.resetScrollbar(),t.$element.trigger("hidden.bs.modal")})},i.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},i.prototype.backdrop=function(e){var o=this,n=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var s=t.support.transition&&n;if(this.$backdrop=t(document.createElement("div")).addClass("modal-backdrop "+n).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",t.proxy(function(t){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(t.target===t.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),s&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!e)return;s?this.$backdrop.one("bsTransitionEnd",e).emulateTransitionEnd(i.BACKDROP_TRANSITION_DURATION):e()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var a=function(){o.removeBackdrop(),e&&e()};t.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",a).emulateTransitionEnd(i.BACKDROP_TRANSITION_DURATION):a()}else e&&e()},i.prototype.handleUpdate=function(){this.adjustDialog()},i.prototype.adjustDialog=function(){var t=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},i.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},i.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth

    '}),i.prototype=t.extend({},t.fn.tooltip.Constructor.prototype),i.prototype.constructor=i,i.prototype.getDefaults=function(){return i.DEFAULTS},i.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();t.find(".popover-title")[this.options.html?"html":"text"](e),t.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof i?"html":"append":"text"](i),t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},i.prototype.hasContent=function(){return this.getTitle()||this.getContent()},i.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},i.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var o=t.fn.popover;t.fn.popover=e,t.fn.popover.Constructor=i,t.fn.popover.noConflict=function(){return t.fn.popover=o,this}}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.carousel"),s=t.extend({},i.DEFAULTS,o.data(),"object"==typeof e&&e),a="string"==typeof e?e:s.slide;n||o.data("bs.carousel",n=new i(this,s)),"number"==typeof e?n.to(e):a?n[a]():s.interval&&n.pause().cycle()})}var i=function(e,i){this.$element=t(e),this.$indicators=this.$element.find(".carousel-indicators"),this.options=i,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",t.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",t.proxy(this.pause,this)).on("mouseleave.bs.carousel",t.proxy(this.cycle,this))};i.VERSION="3.3.6",i.TRANSITION_DURATION=600,i.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},i.prototype.keydown=function(t){if(!/input|textarea/i.test(t.target.tagName)){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()}},i.prototype.cycle=function(e){return e||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(t.proxy(this.next,this),this.options.interval)),this},i.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},i.prototype.getItemForDirection=function(t,e){var i=this.getItemIndex(e),o="prev"==t&&0===i||"next"==t&&i==this.$items.length-1;if(o&&!this.options.wrap)return e;var n="prev"==t?-1:1,s=(i+n)%this.$items.length;return this.$items.eq(s)},i.prototype.to=function(t){var e=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));return t>this.$items.length-1||0>t?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",this.$items.eq(t))},i.prototype.pause=function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&t.support.transition&&(this.$element.trigger(t.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},i.prototype.next=function(){return this.sliding?void 0:this.slide("next")},i.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},i.prototype.slide=function(e,o){var n=this.$element.find(".item.active"),s=o||this.getItemForDirection(e,n),a=this.interval,r="next"==e?"left":"right",l=this;if(s.hasClass("active"))return this.sliding=!1;var h=s[0],d=t.Event("slide.bs.carousel",{relatedTarget:h,direction:r});if(this.$element.trigger(d),!d.isDefaultPrevented()){if(this.sliding=!0,a&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var p=t(this.$indicators.children()[this.getItemIndex(s)]);p&&p.addClass("active")}var c=t.Event("slid.bs.carousel",{relatedTarget:h,direction:r});return t.support.transition&&this.$element.hasClass("slide")?(s.addClass(e),s[0].offsetWidth,n.addClass(r),s.addClass(r),n.one("bsTransitionEnd",function(){s.removeClass([e,r].join(" ")).addClass("active"),n.removeClass(["active",r].join(" ")),l.sliding=!1,setTimeout(function(){l.$element.trigger(c)},0)}).emulateTransitionEnd(i.TRANSITION_DURATION)):(n.removeClass("active"),s.addClass("active"),this.sliding=!1,this.$element.trigger(c)),a&&this.cycle(),this}};var o=t.fn.carousel;t.fn.carousel=e,t.fn.carousel.Constructor=i,t.fn.carousel.noConflict=function(){return t.fn.carousel=o,this};var n=function(i){var o,n=t(this),s=t(n.attr("data-target")||(o=n.attr("href"))&&o.replace(/.*(?=#[^\s]+$)/,""));if(s.hasClass("carousel")){var a=t.extend({},s.data(),n.data()),r=n.attr("data-slide-to");r&&(a.interval=!1),e.call(s,a),r&&s.data("bs.carousel").to(r),i.preventDefault()}};t(document).on("click.bs.carousel.data-api","[data-slide]",n).on("click.bs.carousel.data-api","[data-slide-to]",n),t(window).on("load",function(){t('[data-ride="carousel"]').each(function(){var i=t(this);e.call(i,i.data())})})}(jQuery),+function(t){"use strict";function e(i,o){this.$body=t(document.body),this.$scrollElement=t(t(i).is(document.body)?window:i),this.options=t.extend({},e.DEFAULTS,o),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",t.proxy(this.process,this)),this.refresh(),this.process()}function i(i){return this.each(function(){var o=t(this),n=o.data("bs.scrollspy"),s="object"==typeof i&&i;n||o.data("bs.scrollspy",n=new e(this,s)),"string"==typeof i&&n[i]()})}e.VERSION="3.3.6",e.DEFAULTS={offset:10},e.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},e.prototype.refresh=function(){var e=this,i="offset",o=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),t.isWindow(this.$scrollElement[0])||(i="position",o=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var e=t(this),n=e.data("target")||e.attr("href"),s=/^#./.test(n)&&t(n);return s&&s.length&&s.is(":visible")&&[[s[i]().top+o,n]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){e.offsets.push(this[0]),e.targets.push(this[1])})},e.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),e>=o)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e=n[t]&&(void 0===n[t+1]||e .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),e.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),r?(e[0].offsetWidth,e.addClass("in")):e.removeClass("fade"),e.parent(".dropdown-menu").length&&e.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),n&&n()}var a=o.find("> .active"),r=n&&t.support.transition&&(a.length&&a.hasClass("fade")||!!o.find("> .fade").length);a.length&&r?a.one("bsTransitionEnd",s).emulateTransitionEnd(i.TRANSITION_DURATION):s(),a.removeClass("in")};var o=t.fn.tab;t.fn.tab=e,t.fn.tab.Constructor=i,t.fn.tab.noConflict=function(){return t.fn.tab=o,this};var n=function(i){i.preventDefault(),e.call(t(this),"show")};t(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',n).on("click.bs.tab.data-api",'[data-toggle="pill"]',n)}(jQuery); -------------------------------------------------------------------------------- /dist/scripts/vendor/modernizr.js: -------------------------------------------------------------------------------- 1 | window.Modernizr=function(e,t,n){function r(e){b.cssText=e}function o(e,t){return r(S.join(e+";")+(t||""))}function a(e,t){return typeof e===t}function i(e,t){return!!~(""+e).indexOf(t)}function c(e,t){for(var r in e){var o=e[r];if(!i(o,"-")&&b[o]!==n)return"pfx"==t?o:!0}return!1}function s(e,t,r){for(var o in e){var i=t[e[o]];if(i!==n)return r===!1?e[o]:a(i,"function")?i.bind(r||t):i}return!1}function u(e,t,n){var r=e.charAt(0).toUpperCase()+e.slice(1),o=(e+" "+k.join(r+" ")+r).split(" ");return a(t,"string")||a(t,"undefined")?c(o,t):(o=(e+" "+T.join(r+" ")+r).split(" "),s(o,t,n))}function l(){p.input=function(n){for(var r=0,o=n.length;o>r;r++)j[n[r]]=!!(n[r]in E);return j.list&&(j.list=!(!t.createElement("datalist")||!e.HTMLDataListElement)),j}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),p.inputtypes=function(e){for(var r,o,a,i=0,c=e.length;c>i;i++)E.setAttribute("type",o=e[i]),r="text"!==E.type,r&&(E.value=x,E.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(o)&&E.style.WebkitAppearance!==n?(g.appendChild(E),a=t.defaultView,r=a.getComputedStyle&&"textfield"!==a.getComputedStyle(E,null).WebkitAppearance&&0!==E.offsetHeight,g.removeChild(E)):/^(search|tel)$/.test(o)||(r=/^(url|email)$/.test(o)?E.checkValidity&&E.checkValidity()===!1:E.value!=x)),P[e[i]]=!!r;return P}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var d,f,m="2.8.3",p={},h=!0,g=t.documentElement,v="modernizr",y=t.createElement(v),b=y.style,E=t.createElement("input"),x=":)",w={}.toString,S=" -webkit- -moz- -o- -ms- ".split(" "),C="Webkit Moz O ms",k=C.split(" "),T=C.toLowerCase().split(" "),N={svg:"http://www.w3.org/2000/svg"},M={},P={},j={},$=[],D=$.slice,F=function(e,n,r,o){var a,i,c,s,u=t.createElement("div"),l=t.body,d=l||t.createElement("body");if(parseInt(r,10))for(;r--;)c=t.createElement("div"),c.id=o?o[r]:v+(r+1),u.appendChild(c);return a=["­",'"].join(""),u.id=v,(l?u:d).innerHTML+=a,d.appendChild(u),l||(d.style.background="",d.style.overflow="hidden",s=g.style.overflow,g.style.overflow="hidden",g.appendChild(d)),i=n(u,e),l?u.parentNode.removeChild(u):(d.parentNode.removeChild(d),g.style.overflow=s),!!i},z=function(t){var n=e.matchMedia||e.msMatchMedia;if(n)return n(t)&&n(t).matches||!1;var r;return F("@media "+t+" { #"+v+" { position: absolute; } }",function(t){r="absolute"==(e.getComputedStyle?getComputedStyle(t,null):t.currentStyle).position}),r},A=function(){function e(e,o){o=o||t.createElement(r[e]||"div"),e="on"+e;var i=e in o;return i||(o.setAttribute||(o=t.createElement("div")),o.setAttribute&&o.removeAttribute&&(o.setAttribute(e,""),i=a(o[e],"function"),a(o[e],"undefined")||(o[e]=n),o.removeAttribute(e))),o=null,i}var r={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return e}(),L={}.hasOwnProperty;f=a(L,"undefined")||a(L.call,"undefined")?function(e,t){return t in e&&a(e.constructor.prototype[t],"undefined")}:function(e,t){return L.call(e,t)},Function.prototype.bind||(Function.prototype.bind=function(e){var t=this;if("function"!=typeof t)throw new TypeError;var n=D.call(arguments,1),r=function(){if(this instanceof r){var o=function(){};o.prototype=t.prototype;var a=new o,i=t.apply(a,n.concat(D.call(arguments)));return Object(i)===i?i:a}return t.apply(e,n.concat(D.call(arguments)))};return r}),M.flexbox=function(){return u("flexWrap")},M.flexboxlegacy=function(){return u("boxDirection")},M.canvas=function(){var e=t.createElement("canvas");return!(!e.getContext||!e.getContext("2d"))},M.canvastext=function(){return!(!p.canvas||!a(t.createElement("canvas").getContext("2d").fillText,"function"))},M.webgl=function(){return!!e.WebGLRenderingContext},M.touch=function(){var n;return"ontouchstart"in e||e.DocumentTouch&&t instanceof DocumentTouch?n=!0:F(["@media (",S.join("touch-enabled),("),v,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(e){n=9===e.offsetTop}),n},M.geolocation=function(){return"geolocation"in navigator},M.postmessage=function(){return!!e.postMessage},M.websqldatabase=function(){return!!e.openDatabase},M.indexedDB=function(){return!!u("indexedDB",e)},M.hashchange=function(){return A("hashchange",e)&&(t.documentMode===n||t.documentMode>7)},M.history=function(){return!(!e.history||!history.pushState)},M.draganddrop=function(){var e=t.createElement("div");return"draggable"in e||"ondragstart"in e&&"ondrop"in e},M.websockets=function(){return"WebSocket"in e||"MozWebSocket"in e},M.rgba=function(){return r("background-color:rgba(150,255,150,.5)"),i(b.backgroundColor,"rgba")},M.hsla=function(){return r("background-color:hsla(120,40%,100%,.5)"),i(b.backgroundColor,"rgba")||i(b.backgroundColor,"hsla")},M.multiplebgs=function(){return r("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(b.background)},M.backgroundsize=function(){return u("backgroundSize")},M.borderimage=function(){return u("borderImage")},M.borderradius=function(){return u("borderRadius")},M.boxshadow=function(){return u("boxShadow")},M.textshadow=function(){return""===t.createElement("div").style.textShadow},M.opacity=function(){return o("opacity:.55"),/^0.55$/.test(b.opacity)},M.cssanimations=function(){return u("animationName")},M.csscolumns=function(){return u("columnCount")},M.cssgradients=function(){var e="background-image:",t="gradient(linear,left top,right bottom,from(#9f9),to(white));",n="linear-gradient(left top,#9f9, white);";return r((e+"-webkit- ".split(" ").join(t+e)+S.join(n+e)).slice(0,-e.length)),i(b.backgroundImage,"gradient")},M.cssreflections=function(){return u("boxReflect")},M.csstransforms=function(){return!!u("transform")},M.csstransforms3d=function(){var e=!!u("perspective");return e&&"webkitPerspective"in g.style&&F("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(t,n){e=9===t.offsetLeft&&3===t.offsetHeight}),e},M.csstransitions=function(){return u("transition")},M.fontface=function(){var e;return F('@font-face {font-family:"font";src:url("https://")}',function(n,r){var o=t.getElementById("smodernizr"),a=o.sheet||o.styleSheet,i=a?a.cssRules&&a.cssRules[0]?a.cssRules[0].cssText:a.cssText||"":"";e=/src/i.test(i)&&0===i.indexOf(r.split(" ")[0])}),e},M.generatedcontent=function(){var e;return F(["#",v,"{font:0/0 a}#",v,':after{content:"',x,'";visibility:hidden;font:3px/1 a}'].join(""),function(t){e=t.offsetHeight>=3}),e},M.video=function(){var e=t.createElement("video"),n=!1;try{(n=!!e.canPlayType)&&(n=new Boolean(n),n.ogg=e.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),n.h264=e.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),n.webm=e.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""))}catch(r){}return n},M.audio=function(){var e=t.createElement("audio"),n=!1;try{(n=!!e.canPlayType)&&(n=new Boolean(n),n.ogg=e.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),n.mp3=e.canPlayType("audio/mpeg;").replace(/^no$/,""),n.wav=e.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),n.m4a=(e.canPlayType("audio/x-m4a;")||e.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(r){}return n},M.localstorage=function(){try{return localStorage.setItem(v,v),localStorage.removeItem(v),!0}catch(e){return!1}},M.sessionstorage=function(){try{return sessionStorage.setItem(v,v),sessionStorage.removeItem(v),!0}catch(e){return!1}},M.webworkers=function(){return!!e.Worker},M.applicationcache=function(){return!!e.applicationCache},M.svg=function(){return!!t.createElementNS&&!!t.createElementNS(N.svg,"svg").createSVGRect},M.inlinesvg=function(){var e=t.createElement("div");return e.innerHTML="",(e.firstChild&&e.firstChild.namespaceURI)==N.svg},M.smil=function(){return!!t.createElementNS&&/SVGAnimate/.test(w.call(t.createElementNS(N.svg,"animate")))},M.svgclippaths=function(){return!!t.createElementNS&&/SVGClipPath/.test(w.call(t.createElementNS(N.svg,"clipPath")))};for(var H in M)f(M,H)&&(d=H.toLowerCase(),p[d]=M[H](),$.push((p[d]?"":"no-")+d));return p.input||l(),p.addTest=function(e,t){if("object"==typeof e)for(var r in e)f(e,r)&&p.addTest(r,e[r]);else{if(e=e.toLowerCase(),p[e]!==n)return p;t="function"==typeof t?t():t,"undefined"!=typeof h&&h&&(g.className+=" "+(t?"":"no-")+e),p[e]=t}return p},r(""),y=E=null,function(e,t){function n(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x",r.insertBefore(n.lastChild,r.firstChild)}function r(){var e=y.elements;return"string"==typeof e?e.split(" "):e}function o(e){var t=v[e[h]];return t||(t={},g++,e[h]=g,v[g]=t),t}function a(e,n,r){if(n||(n=t),l)return n.createElement(e);r||(r=o(n));var a;return a=r.cache[e]?r.cache[e].cloneNode():p.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||m.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function i(e,n){if(e||(e=t),l)return e.createDocumentFragment();n=n||o(e);for(var a=n.frag.cloneNode(),i=0,c=r(),s=c.length;s>i;i++)a.createElement(c[i]);return a}function c(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return y.shivMethods?a(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+r().join().replace(/[\w\-]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(y,t.frag)}function s(e){e||(e=t);var r=o(e);return!y.shivCSS||u||r.hasCSS||(r.hasCSS=!!n(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||c(e,r),e}var u,l,d="3.7.0",f=e.html5||{},m=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,h="_html5shiv",g=0,v={};!function(){try{var e=t.createElement("a");e.innerHTML="",u="hidden"in e,l=1==e.childNodes.length||function(){t.createElement("a");var e=t.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(n){u=!0,l=!0}}();var y={elements:f.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:d,shivCSS:f.shivCSS!==!1,supportsUnknownElements:l,shivMethods:f.shivMethods!==!1,type:"default",shivDocument:s,createElement:a,createDocumentFragment:i};e.html5=y,s(t)}(this,t),p._version=m,p._prefixes=S,p._domPrefixes=T,p._cssomPrefixes=k,p.mq=z,p.hasEvent=A,p.testProp=function(e){return c([e])},p.testAllProps=u,p.testStyles=F,p.prefixed=function(e,t,n){return t?u(e,t,n):u(e,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(h?" js "+$.join(" "):""),p}(this,this.document); -------------------------------------------------------------------------------- /dist/styles/vendor.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px!important;margin-bottom:6px!important;max-width:none!important}table.dataTable td,table.dataTable th{box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap td,table.dataTable.nowrap th{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:400;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:400;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc{padding-right:30px}table.dataTable thead>tr>td:active,table.dataTable thead>tr>th:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:8px;right:8px;display:block;font-family:Glyphicons Halflings;opacity:.5}table.dataTable thead .sorting:after{opacity:.2;content:"\e150"}table.dataTable thead .sorting_asc:after{content:"\e155"}table.dataTable thead .sorting_desc:after{content:"\e156"}table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{color:#eee}div.dataTables_scrollHead table.dataTable{margin-bottom:0!important}div.dataTables_scrollBody table{border-top:none;margin-top:0!important;margin-bottom:0!important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child td,div.dataTables_scrollBody table tbody tr:first-child th{border-top:none}div.dataTables_scrollFoot table{margin-top:0!important;border-top:none}@media screen and (max-width:767px){div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable{border-collapse:separate!important}table.table-bordered.dataTable td,table.table-bordered.dataTable th{border-left-width:0}table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable th:last-child{border-right-width:0}div.dataTables_scrollHead table.table-bordered,table.table-bordered.dataTable tbody td,table.table-bordered.dataTable tbody th{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^=col-]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^=col-]:last-child{padding-right:0} -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | // generated on 2016-04-02 using generator-webapp 2.0.0 2 | import gulp from 'gulp'; 3 | import gulpLoadPlugins from 'gulp-load-plugins'; 4 | import browserSync from 'browser-sync'; 5 | import del from 'del'; 6 | import {stream as wiredep} from 'wiredep'; 7 | 8 | const $ = gulpLoadPlugins(); 9 | const reload = browserSync.reload; 10 | 11 | gulp.task('styles', () => { 12 | return gulp.src('app/styles/*.scss') 13 | .pipe($.plumber()) 14 | .pipe($.sourcemaps.init()) 15 | .pipe($.sass.sync({ 16 | outputStyle: 'expanded', 17 | precision: 10, 18 | includePaths: ['.'] 19 | }).on('error', $.sass.logError)) 20 | .pipe($.autoprefixer({browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']})) 21 | .pipe($.sourcemaps.write()) 22 | .pipe(gulp.dest('.tmp/styles')) 23 | .pipe(reload({stream: true})); 24 | }); 25 | 26 | gulp.task('scripts', () => { 27 | return gulp.src('app/scripts/**/*.js') 28 | .pipe($.plumber()) 29 | .pipe($.sourcemaps.init()) 30 | .pipe($.babel()) 31 | .pipe($.sourcemaps.write('.')) 32 | .pipe(gulp.dest('.tmp/scripts')) 33 | .pipe(reload({stream: true})); 34 | }); 35 | 36 | function lint(files, options) { 37 | return () => { 38 | return gulp.src(files) 39 | .pipe(reload({stream: true, once: true})) 40 | .pipe($.eslint(options)) 41 | .pipe($.eslint.format()) 42 | .pipe($.if(!browserSync.active, $.eslint.failAfterError())); 43 | }; 44 | } 45 | const testLintOptions = { 46 | env: { 47 | mocha: true 48 | } 49 | }; 50 | 51 | gulp.task('lint', lint('app/scripts/**/*.js')); 52 | gulp.task('lint:test', lint('test/spec/**/*.js', testLintOptions)); 53 | 54 | gulp.task('html', ['styles', 'scripts'], () => { 55 | return gulp.src('app/*.html') 56 | .pipe($.useref({searchPath: ['.tmp', 'app', '.']})) 57 | .pipe($.if('*.js', $.uglify())) 58 | .pipe($.if('*.css', $.cssnano())) 59 | .pipe($.if('*.html', $.htmlmin({collapseWhitespace: true}))) 60 | .pipe(gulp.dest('dist')); 61 | }); 62 | 63 | gulp.task('images', () => { 64 | return gulp.src('app/images/**/*') 65 | .pipe($.cache($.imagemin({ 66 | progressive: true, 67 | interlaced: true, 68 | // don't remove IDs from SVGs, they are often used 69 | // as hooks for embedding and styling 70 | svgoPlugins: [{cleanupIDs: false}] 71 | }))) 72 | .pipe(gulp.dest('dist/images')); 73 | }); 74 | 75 | gulp.task('fonts', () => { 76 | return gulp.src(require('main-bower-files')('**/*.{eot,svg,ttf,woff,woff2}', function (err) {}) 77 | .concat('app/fonts/**/*')) 78 | .pipe(gulp.dest('.tmp/fonts')) 79 | .pipe(gulp.dest('dist/fonts')); 80 | }); 81 | 82 | gulp.task('extras', () => { 83 | return gulp.src([ 84 | 'app/*.*', 85 | '!app/*.html' 86 | ], { 87 | dot: true 88 | }).pipe(gulp.dest('dist')); 89 | }); 90 | 91 | gulp.task('clean', del.bind(null, ['.tmp', 'dist'])); 92 | 93 | gulp.task('serve', ['styles', 'scripts', 'fonts'], () => { 94 | browserSync({ 95 | notify: false, 96 | port: 9000, 97 | server: { 98 | baseDir: ['.tmp', 'app'], 99 | routes: { 100 | '/bower_components': 'bower_components' 101 | } 102 | } 103 | }); 104 | 105 | gulp.watch([ 106 | 'app/*.html', 107 | 'app/images/**/*', 108 | '.tmp/fonts/**/*' 109 | ]).on('change', reload); 110 | 111 | gulp.watch('app/styles/**/*.scss', ['styles']); 112 | gulp.watch('app/scripts/**/*.js', ['scripts']); 113 | gulp.watch('app/fonts/**/*', ['fonts']); 114 | gulp.watch('bower.json', ['wiredep', 'fonts']); 115 | }); 116 | 117 | gulp.task('serve:dist', () => { 118 | browserSync({ 119 | notify: false, 120 | port: 9000, 121 | server: { 122 | baseDir: ['dist'] 123 | } 124 | }); 125 | }); 126 | 127 | gulp.task('serve:test', ['scripts'], () => { 128 | browserSync({ 129 | notify: false, 130 | port: 9000, 131 | ui: false, 132 | server: { 133 | baseDir: 'test', 134 | routes: { 135 | '/scripts': '.tmp/scripts', 136 | '/bower_components': 'bower_components' 137 | } 138 | } 139 | }); 140 | 141 | gulp.watch('app/scripts/**/*.js', ['scripts']); 142 | gulp.watch('test/spec/**/*.js').on('change', reload); 143 | gulp.watch('test/spec/**/*.js', ['lint:test']); 144 | }); 145 | 146 | // inject bower components 147 | gulp.task('wiredep', () => { 148 | gulp.src('app/styles/*.scss') 149 | .pipe(wiredep({ 150 | ignorePath: /^(\.\.\/)+/ 151 | })) 152 | .pipe(gulp.dest('app/styles')); 153 | 154 | gulp.src('app/*.html') 155 | .pipe(wiredep({ 156 | exclude: ['bootstrap-sass'], 157 | ignorePath: /^(\.\.\/)*\.\./ 158 | })) 159 | .pipe(gulp.dest('app')); 160 | }); 161 | 162 | gulp.task('build', ['lint', 'html', 'images', 'fonts', 'extras'], () => { 163 | return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true})); 164 | }); 165 | 166 | gulp.task('default', ['clean'], () => { 167 | gulp.start('build'); 168 | }); 169 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "davemail", 3 | "version": "2.0.0", 4 | "description": "Decentralised, encrypted, anonymous, offline messaging platform for git.", 5 | "author": "David Apple ", 6 | "license": "MIT", 7 | "private": false, 8 | "engines": { 9 | "node": ">=0.12.0" 10 | }, 11 | "devDependencies": { 12 | "babel-core": "^6.4.0", 13 | "babel-preset-es2015": "^6.3.13", 14 | "browser-sync": "^2.2.1", 15 | "del": "^1.1.1", 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-concat": "^1.0.0", 18 | "gulp": "^3.9.0", 19 | "gulp-autoprefixer": "^3.0.1", 20 | "gulp-babel": "^6.1.1", 21 | "gulp-cache": "^0.4.2", 22 | "gulp-cssnano": "^2.0.0", 23 | "gulp-eslint": "^0.13.2", 24 | "gulp-htmlmin": "^1.3.0", 25 | "gulp-if": "^1.2.5", 26 | "gulp-imagemin": "^2.2.1", 27 | "gulp-load-plugins": "^0.10.0", 28 | "gulp-plumber": "^1.0.1", 29 | "gulp-sass": "^2.0.0", 30 | "gulp-size": "^1.2.1", 31 | "gulp-sourcemaps": "^1.5.0", 32 | "gulp-uglify": "^1.1.0", 33 | "gulp-useref": "^3.0.0", 34 | "main-bower-files": "^2.5.0", 35 | "wiredep": "^2.2.2" 36 | }, 37 | "eslintConfig": { 38 | "env": { 39 | "es6": true, 40 | "node": true, 41 | "browser": true 42 | }, 43 | "rules": { 44 | "quotes": [ 45 | 2, 46 | "single" 47 | ], 48 | "eqeqeq": "warn", 49 | "strict": "off" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Spec Runner 6 | 7 | 8 | 9 |
    10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/spec/test.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | describe('Give it some context', function () { 5 | describe('maybe a bit more context here', function () { 6 | it('should run here few assertions', function () { 7 | 8 | }); 9 | }); 10 | }); 11 | })(); 12 | --------------------------------------------------------------------------------