321 Commits
Author SHA1 Message Date
ceda_ei a541630848 Add /:id/raw 2019-07-17 16:38:13 +05:30
ceda_ei e067323714 Change about.md 2019-07-17 16:30:37 +05:30
John Crepezzi b866c33c93 Merge pull request #173 from sebastiansterk/master
removed padding for #box for correct view
2019-04-05 17:30:42 -04:00
John Crepezzi f3838ab4a8 Merge pull request #251 from seejohnrun/handle-redis-disconnect
Handle redis error and re-establish connection
2018-09-19 10:38:34 -04:00
John Crepezzi bf2b1c957a Handle redis error and re-establish connection 2018-09-19 10:37:34 -04:00
John Crepezzi ee1c1c0856 Merge pull request #231 from seejohnrun/ensure-raw-utf8
Added charset to raw content type
2018-07-12 14:26:05 -04:00
John Crepezzi b087ac8dd1 Added charset to raw content type
Closes #230
2018-07-12 14:25:27 -04:00
John Crepezzi d922667f56 Merge pull request #221 from PassTheMayo/patch-1
Fixed unnecessary logging when document not found
2018-04-30 19:45:16 -04:00
Jacob Gunther 5f6fefa7a6 Fixed unnecessary logging when document not found 2018-04-30 16:40:28 -05:00
John Crepezzi faa7e679ca Merge pull request #216 from PassTheMayo/master
Fixed RethinkDB document store
2018-04-16 11:53:28 -04:00
Jacob Gunther cd3bf26dbe Use local method for md5 2018-04-16 10:52:53 -05:00
Jacob Gunther 830dc1bc43 Use uploads table 2018-04-15 23:16:39 -05:00
Jacob Gunther dc0f151a7f Fixed bug in RethinkDB document store and use classes 2018-04-15 23:16:08 -05:00
John Crepezzi 7f625e22f7 Merge pull request #203 from seejohnrun/rewrite_memcached
Rewrite the memcached client
2018-04-13 16:10:42 -04:00
John Crepezzi 528b7b07a8 Merge pull request #215 from Razzeee/patch-1
Update docs to real defaults
2018-04-09 13:08:36 -04:00
Razzeee 2b81e67ce7 Update docs to real defaults 2018-04-09 19:05:21 +02:00
John Crepezzi 827e7b51b5 Rewrite the memcached client
* Update syntax to ES6
* Use `memcached` instead of `memcache`
* Fix restrictions where expirations weren't pushed forward on GET
* Fix a bug where we were unnecessarily bumping expirations on key search

Closes #201
2018-02-16 09:52:44 -05:00
John Crepezzi ad7702aaf4 Merge pull request #194 from szepeviktor/patch-1
Change to HTTPS in about.md
2018-01-22 10:30:12 -05:00
Viktor Szépe f5fbc8d19e Change to HTTPS in about.md
Please also change the repo URL here on GitHub
2018-01-22 14:51:15 +01:00
John Crepezzi 0a8923bf12 Merge pull request #192 from C0rn3j/master
Add note about paste expiration, cosmetic fixes.
2017-12-30 20:24:01 -05:00
Martin 4d572a2ec0 convert relative path to absolute 2017-12-30 17:11:29 +01:00
Martin d9a53d3e6e Add note about paste expiration, cosmetic fixes. 2017-12-29 20:42:11 +01:00
John Crepezzi 8da37ea5de Merge pull request #190 from PassTheMayo/patch-1
Oh noes! I didn't even notice that I had a typo...
2017-12-11 10:51:12 -05:00
Jacob Gunther ff0fccd6c2 Oh noes! I didn't even notice that I had a typo... 2017-12-11 09:50:50 -06:00
John Crepezzi 63c4576633 Merge pull request #189 from PassTheMayo/master
Added RethinkDB storage option & fixed config to use proper JSON
2017-12-11 10:46:45 -05:00
Jacob Gunther b31d143bcd Revert config.js to previous state 2017-12-11 09:45:37 -06:00
Jacob Gunther 0d8aec8d61 Oops, forgot to fix that file name 2017-12-11 09:44:23 -06:00
Jacob Gunther 1f9fdd205d Undid changes to server.js 2017-12-11 09:28:27 -06:00
Jacob Gunther cdd0cf3739 Fixed requested changes to RethinkDB handler 2017-12-11 09:27:44 -06:00
PassTheMayo ba5c6b8d16 Added RethinkDB storage option & fixed config to use proper JSON 2017-12-09 18:34:00 -06:00
John Crepezzi cfef588283 Merge pull request #181 from seejohnrun/simplify_uglify
Upgrade uglify and simplify usage
2017-10-31 21:20:23 -04:00
John Crepezzi 318c5f7ba6 Upgrade uglify and simplify usage
- Upgrade to the most recent version of uglify
- Use the `UglifyJS.minify(code)` helper which does exactly what we want
2017-10-31 21:19:22 -04:00
John Crepezzi ee03e7cd78 Merge pull request #180 from seejohnrun/es6_generators
ES6 generators
2017-10-31 21:11:32 -04:00
John Crepezzi 3b6934e348 Phonetic key generator to es6 and add some tests 2017-10-31 21:10:25 -04:00
John Crepezzi f161cc33b4 Added tests and converted dictionary key generator to es6 2017-10-31 20:55:59 -04:00
John Crepezzi 40f1f2588e Update some es6 2017-10-31 20:55:51 -04:00
John Crepezzi e4e025f67e Convert random generator to es6 and add some specs for it directly 2017-10-31 20:40:43 -04:00
John Crepezzi e12805a8aa Merge pull request #179 from seejohnrun/upgrade_testing
Upgrade testing libraries
2017-10-31 20:04:37 -04:00
John Crepezzi e76c845f16 Upgrade testing libraries
- Upgrade mocha
- Remove should due to limited usage and old style (at least by rspec standards)
- Move spec -> test which is the default
- Update tests accordingly for the above
2017-10-31 20:03:30 -04:00
John Crepezzi 072418695e Merge pull request #178 from seejohnrun/upgrade_highlight
Upgrade highlight.js
2017-10-31 19:49:20 -04:00
John Crepezzi 584b66bc66 Upgrade highlight.js 2017-10-31 19:48:55 -04:00
Sebastian Sterk f8db455f74 removed padding for #box for correct view 2017-10-13 15:13:04 +02:00
John Crepezzi f19c5d1049 Fix typo in README
Closes #165
2017-08-03 11:45:51 +00:00
John Crepezzi c5b859ec98 Bump node engine version & fix asset compression on start 2017-07-11 21:13:33 -04:00
John Crepezzi 2ee93a7409 Merge pull request #160 from seejohnrun/complete_eslint
Fix eslint
2017-06-26 12:38:57 -04:00
John Crepezzi bf1dbb68b8 Fix eslint 2017-06-26 12:38:17 -04:00
John Crepezzi cf28e23d8e Merge pull request #159 from seejohnrun/add_eslint
Added eslint and fixed an issue from #158
2017-06-26 12:29:10 -04:00
John Crepezzi 5939dec185 Added eslint and fixed an issue from #158 2017-06-26 12:19:36 -04:00
John Crepezzi 3ed1d775ac Merge pull request #158 from KlasafGeijerstam/master
Added dictionary key generator
2017-06-26 12:11:44 -04:00
John Crepezzi 87b1c76aaf One more 2017-06-26 12:11:19 -04:00
John Crepezzi 4599203bdf A few style nit-picks 2017-06-26 12:10:57 -04:00
Klas af Geijerstam d66bc9a6c4 Removed unused lines 2017-06-26 18:09:13 +02:00
Klas af Geijerstam 80f0618736 Updated dictionary.js
Now expects a newline separated dictionary, supports both \n and \n\r
2017-06-26 18:03:18 +02:00
Klas af Geijerstam ac2bceefbb Added missing ) 2017-06-26 17:42:24 +02:00
Klas af Geijerstam dbf4f6b5dd Removed usage of random-js
Replaced random-js with vanilla JS random
2017-06-26 17:39:32 +02:00
Klas af Geijerstam 8e9205cecc Update dictionary.js 2017-06-26 17:37:04 +02:00
Klas af Geijerstam e54a860172 Added dictionary.js
A key generator that uses a dictionary to create its keys
2017-06-26 17:17:52 +02:00
John Crepezzi 5a8697cdd8 Fix typo in about.md 2017-05-02 17:32:34 -04:00
John Crepezzi 091ea973a8 Merge pull request #138 from Wohlstand/patch-2
Added a note about Redis's password field
2017-04-21 07:51:23 -04:00
John Crepezzi 939b7221ab Merge pull request #146 from seejohnrun/dont_expire_static_documents
Don't expire static documents on raw read
2017-01-28 11:58:12 -05:00
John Crepezzi 934aaf7f51 Don't expire static documents on raw read 2017-01-28 11:57:25 -05:00
Vitaly Novichkov 930e21ccb7 Added a note about Redis's password field 2016-11-06 02:25:51 +04:00
John Crepezzi eb5c8eef6a Merge pull request #135 from seejohnrun/horizontal_scroll_fix
Fix horizontal scroll overflow
2016-09-30 10:40:15 -05:00
John Crepezzi 03dd611a86 Fix horizontal scroll overflow
Caused by highlight.js upgrade
2016-09-30 09:57:46 -05:00
John Crepezzi f24376b192 Merge pull request #129 from Wohlstand/patch-1
Fix working error under Firefox
2016-09-19 09:36:56 -04:00
Vitaly Novichkov eea359d0ec Update index.html
Short charset command better for HTML5
2016-09-13 15:11:20 +04:00
John Crepezzi af9a71549b Upgrade highlight.js
Also adds swift support

Closes #69
2016-09-12 20:10:15 -04:00
John Crepezzi 3178676fba Merge pull request #131 from seejohnrun/update_doc
Update documentation to mention redis-server
2016-08-22 13:23:11 -04:00
John Crepezzi 3bdfab8219 Update documentation to mention redis-server 2016-08-22 13:22:49 -04:00
John Crepezzi a3a24d9765 Merge pull request #127 from Gwemox/master
Compatibility with screen reader
2016-08-17 14:03:13 -04:00
Vitaly Novichkov 8afb53e77e Fix working error under Firefox
On some computers because undeclared charset, highlight.min.js parsing incorrectly while some charsets (For example, Cyrillic-1251) are toggled. Problem is going away when I manually toggling Europan or UTF-8 charset.
2016-08-03 14:15:58 +04:00
Thibault Buathier d6d9cf40f9 Compatibility with screen reader 2016-07-30 16:15:53 +02:00
Thibault Buathier 1010a142e2 Compatibility with screen reader 2016-07-30 16:15:26 +02:00
John Crepezzi 0209375865 Revert "Added cloudron external provider"
This reverts commit 00a9d9c312.
2016-03-12 13:09:28 -05:00
John Crepezzi 00a9d9c312 Added cloudron external provider 2016-03-12 13:07:58 -05:00
John Crepezzi 6835eef468 Merge pull request #109 from seejohnrun/rate_limiting
Added user-configurable rate limiting
2016-03-10 11:44:57 -10:00
John Crepezzi 4626fd9c8d Merge pull request #81 from pangeacake/master
Add postgres information to README.md
2016-03-06 19:06:04 -05:00
John Crepezzi fbb6e63c37 Added a note to the README 2016-03-06 16:34:33 -05:00
John Crepezzi 84c909a5db Added user-configurable rate limiting 2016-03-06 16:20:40 -05:00
John Crepezzi 45e19bc7cc fix indentation 2015-12-27 12:59:59 -05:00
John Crepezzi 233bc6ff16 Merge pull request #77 from abn/redis-auth
Support authentication for redis store if password provided
2015-12-27 12:58:24 -05:00
PangeaCake 360b325ced Smaller typo 2015-01-07 14:30:12 -08:00
PangeaCake e93f98112b Add pg as dependency and update node version
One of the dependencies seemed to be broken with the previous node version, but this node version worked perfectly
2015-01-07 14:27:46 -08:00
PangeaCake 05cb051bc8 Tiny fix 2015-01-07 14:25:43 -08:00
PangeaCake 031cdd738a Add postgres information to README.md 2015-01-07 14:24:50 -08:00
Arun Babu Neelicattu c92ab077c0 Support authentication for redis store if password provided 2014-11-21 23:17:19 +10:00
John Crepezzi 6c31389327 Merge pull request #64 from lidl/master
Make table creation comment a one-liner.
2014-07-16 07:54:00 -04:00
lidl a8d4f3c300 Make table creation comment a one-liner. 2014-06-27 18:40:05 -04:00
John Crepezzi ab029eae2f Added postgres adapter 2014-06-09 16:50:43 -04:00
John Crepezzi 447d0aae76 PG basis 2014-06-09 14:48:35 -04:00
John Crepezzi 4870158430 Merge branch 'master' of github.com:seejohnrun/haste-server 2014-04-21 14:17:09 -04:00
John Crepezzi 0471b059a0 Support a form-data POST API
Closes #54
2014-04-21 14:16:23 -04:00
John Crepezzi 5bbe50b481 Merge pull request #59 from jomo/phonetic
Phonetic key improvements
2014-04-15 11:00:49 -04:00
JonApps bda2749879 oops 🍺 2014-03-25 02:23:31 +01:00
JonApps 028aa96b13 phonetic keys can begin with vowel + added missing \'z\' to consontants 2014-03-25 02:20:05 +01:00
John Crepezzi 2deda5b68a Merge pull request #56 from joeykrim/patch-1
Small typo
2014-02-27 19:26:31 -05:00
joeykrim ee7098457e Small typo
Changed "its all open source" to "it's all open source"
2014-02-27 17:57:37 -05:00
John Crepezzi 7a08960414 Merge branch 'master' of github.com:seejohnrun/haste-server 2013-11-24 11:54:34 -05:00
John Crepezzi 89909747f1 Don't depend on err.message for redis errors [#49] 2013-11-24 11:54:01 -05:00
John Crepezzi 202e695e07 Remove GA from index.html on Master 2013-10-31 08:44:33 -04:00
John Crepezzi 48e8e79659 Remove support from README 2013-08-13 13:06:37 -04:00
John Crepezzi abb49f2cf3 update about.md 2013-03-12 21:59:10 -04:00
John Crepezzi d1cd2a5213 Proper 2013-01-11 10:00:35 -08:00
John Crepezzi 27317844e0 Remove nl 2013-01-11 09:57:10 -08:00
John Crepezzi ee74e2fa90 Merge branch 'production' of github.com:seejohnrun/haste-server into production 2012-12-29 18:15:45 -05:00
John Crepezzi 5d8bd2e6f8 Merge branch 'master' into production 2012-12-29 18:15:32 -05:00
John Crepezzi cd4c7aeab8 Merge pull request #37 from naftis/patch-1
Bugfix to solarized_dark.css
2012-12-28 07:10:36 -08:00
naftis e37c3cf1b9 Bugfix to solarized_dark.css
Fixed bug with font-style: italic and WebKit.
WebKit makes line-height bigger, when italic is used.
2012-12-28 16:11:21 +02:00
John Crepezzi 8858bab985 Merge branch 'master' into production 2012-12-23 10:54:15 -05:00
John Crepezzi afb0c332cc Added shift modifier to twitter shortcut
Closes #29
2012-12-23 10:53:53 -05:00
John Crepezzi 82c58c5c0c Merge branch 'master' into production 2012-12-19 08:18:14 -05:00
John Crepezzi 46bdd27431 Fix for type name ;)
Closes #28
2012-12-19 08:17:52 -05:00
John Crepezzi 1adfba1a37 Merge branch 'master' into production 2012-12-19 08:13:36 -05:00
John Crepezzi 54e55b1b0d Added JSON to extension map (JS)
Closes #28
2012-12-19 08:12:08 -05:00
John Crepezzi 08d37cc7f7 Added support section 2012-10-22 14:40:52 -04:00
John Crepezzi aa781957e8 Update Copyright 2012-09-27 13:46:27 -04:00
John Crepezzi c00477c93c Update Copyright 2012-09-27 13:46:09 -04:00
John Crepezzi 035f09ac05 GA 2012-09-27 13:43:53 -04:00
John Crepezzi 36e00bb29e Remove 'localhost' references 2012-09-27 12:03:52 -04:00
John Crepezzi 10623873e8 Allow host setting by ENV 2012-09-27 12:01:00 -04:00
John Crepezzi e536ba1019 Move to an available npm version 2012-09-27 11:56:49 -04:00
John Crepezzi 85fc36d710 Update npm version 2012-09-27 11:56:15 -04:00
John Crepezzi 5d5ae164f3 Set up node engine version 2012-09-27 11:54:40 -04:00
John Crepezzi 79309c75df Bump version to 0.1.0 2012-09-27 11:51:15 -04:00
John Crepezzi 4b58c8d356 Added more loggin 2012-09-27 11:50:56 -04:00
John Crepezzi 8f0d6260b0 change how redistogo install works 2012-09-27 11:50:12 -04:00
John Crepezzi 93a83a35da Logging 2012-09-27 11:47:23 -04:00
John Crepezzi 4efc5d47d9 Allow redistogo 2012-09-27 11:46:53 -04:00
John Crepezzi ff8ef54e34 Procfile 2012-09-27 11:38:14 -04:00
John Crepezzi 814a49812a Update server config path 2012-09-19 14:28:52 -04:00
John Crepezzi e0610bc1be Fix multiple document loading
Closes #32
2012-08-13 11:33:20 -04:00
John Crepezzi 962976c204 Pad the right 2012-06-22 15:33:07 -04:00
John Crepezzi 16080bdc16 Update description - preparing for npm push 2012-04-21 23:49:39 -04:00
John Crepezzi 20ce741341 Fix indentation 2012-04-07 23:51:48 -04:00
John Crepezzi 13bb094fb3 Revert "Refactor frontend"
This reverts commit 1950cc8db0.
2012-03-19 18:17:39 -04:00
John Crepezzi b43a55ffda Merge pull request #25 from zaeleus/backbone
Refactor frontend
2012-03-19 15:11:08 -07:00
John Crepezzi 45cbdcce70 Force down connect version 2012-03-02 14:07:59 -05:00
Michael Macias 1950cc8db0 Refactor frontend
* restructured JavaScript using backbone.js
* replaced highlight.js with CodeMirror for its editor
* added CodeMirror Solarized (dark) theme based on Ethan Schoonover's solarized.vim
* changed `POST /document` to accept real JSON
* cleaned up template and stylesheet
2012-02-18 02:40:56 -06:00
John Crepezzi 90cfe0ec57 Upgrade jquery to 1.7.1 2012-02-07 17:52:48 -05:00
John Crepezzi 87e28548b9 Explicitly set encoding
Closes #24
2012-02-07 17:52:31 -05:00
John Crepezzi ca9d4c18f7 Added a note on WinHaste to about.md 2012-01-27 09:47:56 -05:00
John Crepezzi f147c05ff1 Add more detail to README.md 2012-01-27 09:46:24 -05:00
John Crepezzi 7a2851aeeb Merge branch 'master' of github.com:seejohnrun/haste-server 2012-01-24 22:29:38 -05:00
John Crepezzi ef96704f2c Basic coffeescript highlighting
From https://github.com/dnagir/highlightjs-coffeescript

Closes #2
2012-01-24 22:28:58 -05:00
John Crepezzi 8b7ac341e7 FileDocumentStore fix
Closes #20
2012-01-24 00:01:38 -05:00
John Crepezzi 713914aecd Merge pull request #18 from tfausak/patch-1
Fix typo in about.md ("easist" -> "easiest").
2012-01-23 19:27:24 -08:00
Taylor Fausak 36e7a43c14 Fix typo in about.md ("easist" -> "easiest"). 2012-01-23 20:12:33 -06:00
John Crepezzi 047a686248 Open raw in same window 2012-01-23 11:40:09 -05:00
John Crepezzi 347ba57ad3 Merge branch 'raw_icon' 2012-01-23 11:38:36 -05:00
Brian Dawson d2bd78956b Merge branch 'master' of github.com:seejohnrun/haste-server
Conflicts:
	static/function-icons.png
2012-01-22 23:42:41 -05:00
Brian Dawson 1fe81d2447 update function icons 2012-01-22 23:41:40 -05:00
John Crepezzi f37d1ad401 Clean up some code and move document stores into subfolder 2012-01-21 15:19:55 -05:00
John Crepezzi 483fce891d Added memcached support 2012-01-17 14:43:33 -05:00
John Crepezzi 6e4c087319 Remove hashlib dependency and switch to mocha for testing 2012-01-13 11:17:15 -05:00
John Crepezzi 844a2efb02 Added support for raw button 2012-01-10 23:06:44 -05:00
John Crepezzi b251978422 Merge pull request #15 from zaeleus/html_escape
Escape document when using the txt extension
2012-01-09 20:43:39 -08:00
John Crepezzi 9fdcd08591 Revert "updated icon set to include "raw/just text""
This reverts commit 31a701d491.
2012-01-09 22:12:00 -05:00
Michael Macias d87c3b7d61 Escape document when using the txt extension 2012-01-08 23:47:07 -06:00
Brian Dawson 31a701d491 updated icon set to include "raw/just text" 2012-01-09 00:41:30 -05:00
John Crepezzi cc65e98940 Added support for phonetic key naming
Closes #7
2012-01-07 11:35:11 -05:00
John Crepezzi a958c66249 Merge pull request #14 from grampajoe/cancelling
Cancellation should only last as long as the handler
2011-12-19 12:42:12 -08:00
Joe Friedl 8c2add94a2 Cancellation should only last as long as the handler 2011-12-19 14:20:22 -06:00
John Crepezzi 71c791c113 Merge pull request #13 from grampajoe/error-messages
Error messages
2011-12-19 11:31:17 -08:00
Joe Friedl b38d2375ee Merge branch 'master' into error-messages 2011-12-19 11:57:23 -06:00
Joe Friedl 6145a938e3 Error messages in the UI 2011-12-19 11:44:12 -06:00
John Crepezzi 7a946f4967 Merge pull request #12 from grampajoe/master
Fixed error in error message.
2011-12-18 17:58:07 -08:00
Joe Friedl 87c935ac47 Fixed error in error message. 2011-12-18 18:51:23 -06:00
John Crepezzi 14a23388a8 Added non-standard but desirable robots.txt 2011-12-16 08:18:04 -05:00
John Crepezzi 44f7ab3f33 Added the ability to retrieve raw documents
Closes #10
2011-12-16 07:57:49 -05:00
John Crepezzi 8add4917d5 Change the line number color 2011-12-15 21:48:48 -05:00
John Crepezzi 3a6b36ebaa Working line number support - just waiting on a final color from @bridawson
[#5]
2011-12-15 21:27:23 -05:00
John Crepezzi 49bb449141 Back button fix 2011-12-15 14:23:09 -05:00
John Crepezzi 8e46ee620f Merge pull request #11 from nshontz/patch-1
Including dependencies for osx and linux for installation
2011-12-15 07:55:03 -08:00
nshontz 907a7c0929 Including dependencies for osx and linux for installation, these are a couple things I ran into while getting set up. 2011-12-15 08:45:28 -07:00
John Crepezzi 242d8475cf Update static/solarized_dark.css 2011-12-12 16:40:47 -05:00
John Crepezzi 8e3bc9826b Merge pull request #8 from muloka/patch-1
Included license information of other included components.
2011-12-05 11:57:15 -08:00
Louis Galipeau 335ae24dc5 Included license information of other included components. 2011-12-05 15:49:41 -04:00
John Crepezzi 2fdcd316f7 Added a favicon 2011-11-29 20:24:53 -05:00
John Crepezzi da407cfbb6 Update about.md for linux xsel 2011-11-29 20:23:30 -05:00
John Crepezzi 0f02d83d24 remove ^L for saving 2011-11-29 20:11:09 -05:00
John Crepezzi 615fedd6c7 Fix doctype 2011-11-29 13:40:13 -05:00
John Crepezzi 4e20ea078f Added html5 doctype 2011-11-29 13:13:10 -05:00
John Crepezzi 15bd62836b Change how twitter link is built 2011-11-29 12:06:49 -05:00
John Crepezzi 8eb1b54615 Added more detail to about page 2011-11-29 12:05:04 -05:00
John Crepezzi 0e292ad21b support .txt type 2011-11-29 10:44:05 -05:00
John Crepezzi 9378f2b2e4 Automatically add file extensions 2011-11-29 10:39:12 -05:00
John Crepezzi 344d1fec7b Add more detail to README 2011-11-29 09:25:22 -05:00
John Crepezzi d1ff598f50 Update about 2011-11-29 09:21:01 -05:00
John Crepezzi 6448139396 Merge branch 'master' of codeplane.com:seejohnrun/haste-server
Conflicts:
	README.md
2011-11-29 09:17:49 -05:00
John Crepezzi 87f5af3194 Clean up README 2011-11-29 09:17:04 -05:00
John Crepezzi 82af7a221a Clean up README 2011-11-29 09:15:16 -05:00
John Crepezzi 01d9337f10 Clean up redis test to exit properly 2011-11-28 20:56:41 -05:00
John Crepezzi 844e664cb5 Added some tests for redis document store 2011-11-28 20:51:04 -05:00
John Crepezzi 68c4fc2534 Update TODO 2011-11-28 19:58:32 -05:00
John Crepezzi 83959a77fc Fix bottom margin issue on box 2011-11-28 19:58:27 -05:00
John Crepezzi 565830214b Start in on the tests 2011-11-28 16:46:59 -05:00
John Crepezzi 43e5667ff9 Remove finished TODO 2011-11-28 14:50:04 -05:00
John Crepezzi f755b675d0 Bump key length to 10 2011-11-28 13:17:13 -05:00
John Crepezzi 9157a0227d Remove clipboard 2011-11-28 13:02:48 -05:00
John Crepezzi 8eca87ce03 Change image 2011-11-28 10:50:33 -05:00
John Crepezzi 2de05d9055 Change expiration to 30 days 2011-11-28 10:37:39 -05:00
John Crepezzi a1ba8b6b71 Added email for brian dawson 2011-11-28 10:35:08 -05:00
John Crepezzi 96b3249b09 Change image colors 2011-11-28 10:32:33 -05:00
John Crepezzi 81c41c0f37 Put in compressed asset 2011-11-28 10:30:54 -05:00
John Crepezzi 52198b97b2 Get rid of the CSS #key .box* nonsense 2011-11-28 09:56:06 -05:00
John Crepezzi 17897e8155 remove static jquery copy 2011-11-28 09:54:31 -05:00
John Crepezzi f651c30981 Merge branch 'master' of codeplane.com:seejohnrun/haste-server
Conflicts:
	TODO.md
2011-11-28 09:48:28 -05:00
John Crepezzi 9e046ba8eb Added the arrow pointer in 2011-11-28 09:42:26 -05:00
John Crepezzi a5459fc29b Added a TODO 2011-11-28 01:29:09 -05:00
John Crepezzi 1ed980150c Fix annoying chrome dual-load bug 2011-11-28 01:27:41 -05:00
John Crepezzi 6e2955d60c Warn on no setExpire in file store 2011-11-28 01:17:46 -05:00
John Crepezzi 92e0f579ca Kick expirations back on view 2011-11-28 01:13:14 -05:00
John Crepezzi cd9bf18d29 Remove a TODO 2011-11-28 00:56:57 -05:00
John Crepezzi 895485e410 Fix highlighting bug 2011-11-28 00:54:24 -05:00
John Crepezzi 29651ebfd5 More about page changes 2011-11-28 00:51:43 -05:00
John Crepezzi 983749e4af Update TODO 2011-11-28 00:47:35 -05:00
John Crepezzi 0ea5b65eba Use about.md instead of about 2011-11-27 23:41:18 -05:00
John Crepezzi 2a3a9046d8 Proper markdown highlighting 2011-11-27 23:39:09 -05:00
John Crepezzi 481155194a Merge branch 'master' of codeplane.com:seejohnrun/haste-server
Conflicts:
	TODO.md
2011-11-27 23:30:20 -05:00
John Crepezzi 0875ba6252 Auto-compress javascript assets 2011-11-27 15:49:17 -05:00
John Crepezzi d3ba2e4b5b Remove TODO 2011-11-27 15:35:46 -05:00
John Crepezzi 4233e58995 Added copy URL functionality 2011-11-27 15:34:09 -05:00
John Crepezzi c4a5184962 Clean up TODO 2011-11-27 14:48:33 -05:00
John Crepezzi 85fac80a6d Put staticCache back in 2011-11-27 14:47:36 -05:00
John Crepezzi 0a0e1636bc Allow the /about page 2011-11-27 14:37:38 -05:00
John Crepezzi b47e5ad2a8 Update TODO 2011-11-27 12:16:06 -05:00
John Crepezzi d262c9f853 use compressed application.js 2011-11-25 10:28:26 -05:00
John Crepezzi fb0c439879 temporarily remove staticCache 2011-11-23 22:01:22 -05:00
John Crepezzi e0941d5ac9 Updated about page 2011-11-23 17:11:55 -05:00
John Crepezzi 591fd456d6 Change application name 2011-11-23 17:09:12 -05:00
John Crepezzi 8281d382e4 on highlight error, return data 2011-11-23 16:58:56 -05:00
John Crepezzi 6285d665ad Expand extension map and catch highlight errors 2011-11-23 16:55:26 -05:00
John Crepezzi 12aa622c2d Clean up the router 2011-11-23 16:34:22 -05:00
John Crepezzi a7aec372d5 extensions work again 2011-11-23 16:32:20 -05:00
John Crepezzi d6468ad5fb Fixed bug that was preventing document lookup 2011-11-23 15:45:28 -05:00
John Crepezzi 607d3eb3ac Remove the static handler 2011-11-23 15:27:02 -05:00
John Crepezzi b598e73d3f Update TODO 2011-11-23 13:19:43 -05:00
John Crepezzi 6906ad4253 Clean up TODO 2011-11-23 13:17:22 -05:00
John Crepezzi 167c7c4adb Use the new router 2011-11-23 13:14:18 -05:00
John Crepezzi 1dbaa54811 CDN assets 2011-11-23 12:28:08 -05:00
John Crepezzi a1803305fb Change hover state for non-enabled 2011-11-23 12:12:01 -05:00
John Crepezzi 62e04cbf5b Merge branch 'master' of codeplane.com:seejohnrun/haste-server 2011-11-23 11:34:31 -05:00
John Crepezzi 7f4cae57f9 Fix document handler regex 2011-11-23 11:34:08 -05:00
John Crepezzi 315333d8eb Merge branch 'master' of codeplane.com:seejohnrun/haste-server 2011-11-23 11:33:02 -05:00
John Crepezzi 2089a14ad7 TODO 2011-11-23 11:32:49 -05:00
John Crepezzi f601d9f159 Implement redesign of key 2011-11-23 11:31:50 -05:00
John Crepezzi ab47aeb88b Fix bug in document handler 2011-11-22 20:38:52 -05:00
John Crepezzi 051a545a55 Move todo to todo.md 2011-11-22 20:34:34 -05:00
John Crepezzi 5d889662ef Added a TODO 2011-11-22 20:30:24 -05:00
John Crepezzi ec0d419c61 Allow forcing of highlight type 2011-11-22 20:29:46 -05:00
John Crepezzi 56bf98daac More robots.txt work 2011-11-22 20:01:09 -05:00
John Crepezzi 2299819781 Added robots.txt 2011-11-22 19:59:03 -05:00
John Crepezzi 5b66695ca6 Update TODO 2011-11-22 16:51:35 -05:00
John Crepezzi f81b7ec593 Update about and TODO 2011-11-22 09:53:02 -05:00
John Crepezzi e403549e13 Added static document loading on start 2011-11-22 09:22:37 -05:00
John Crepezzi 32b4f842b7 serve 404 when not possible key 2011-11-21 23:13:46 -05:00
John Crepezzi 9ed330bdae Make static asset caching an option 2011-11-21 23:00:28 -05:00
John Crepezzi 1382ec47b2 DRY up the static cache 2011-11-21 22:53:50 -05:00
John Crepezzi 83cb68ada2 cache static assets in memory 2011-11-21 22:19:43 -05:00
John Crepezzi e4da28de8a Remove TODO 2011-11-21 22:04:41 -05:00
John Crepezzi 32d49385a1 Remove debug logging 2011-11-21 22:04:12 -05:00
John Crepezzi d0e3e4cd02 Support for redis expiration 2011-11-21 22:03:50 -05:00
John Crepezzi 0f2075fcda Ensure conflict resolution in keyspace 2011-11-21 21:48:09 -05:00
John Crepezzi 4ed87c4ec7 Fix the key 2011-11-21 20:52:35 -05:00
John Crepezzi 025dfcfe26 Remove save when on locked screen 2011-11-21 20:47:29 -05:00
John Crepezzi 39ffbc7f49 Update TODO 2011-11-21 10:18:48 -05:00
John Crepezzi a9e29c2986 Added support for haste maximum size 2011-11-21 10:17:23 -05:00
John Crepezzi 29a600fe87 Fix ^n bug while editing 2011-11-21 10:01:33 -05:00
John Crepezzi 4d56fc0e61 More browser support 2011-11-21 09:59:14 -05:00
John Crepezzi 9fa99fe69d Fixes for Firefox 2011-11-21 09:56:33 -05:00
John Crepezzi 9638baffdb Make twitter posting an option 2011-11-19 01:00:04 -05:00
John Crepezzi 6499ad3190 Clean up animations 2011-11-19 00:53:38 -05:00
John Crepezzi 73be6e31d9 Added TODO 2011-11-19 00:34:23 -05:00
John Crepezzi af02375b7c Show certain options only sometimes 2011-11-19 00:30:14 -05:00
John Crepezzi f54712f9d9 Added twitter functionality 2011-11-19 00:23:53 -05:00
John Crepezzi b9e9bd154c Fix some annoying visual quirks 2011-11-19 00:02:11 -05:00
John Crepezzi a213bdf9da Update TODO 2011-11-18 23:28:53 -05:00
John Crepezzi b6eef4b628 Update README 2011-11-18 20:04:50 -05:00
John Crepezzi bece4598f7 Remove haste client 2011-11-18 20:03:39 -05:00
John Crepezzi 44350ce9e6 Clean up redis store 2011-11-18 19:59:41 -05:00
John Crepezzi 00e2ca8d29 Remove done TODO 2011-11-18 19:57:36 -05:00
John Crepezzi a2d17b28df Remove redundant package dependency 2011-11-18 19:56:09 -05:00
John Crepezzi a1d5f79708 Added Redis store support 2011-11-18 19:55:14 -05:00
John Crepezzi 26c148ff37 Added TODO 2011-11-18 19:10:23 -05:00
John Crepezzi 6c85c23c6d Added README 2011-11-18 18:45:20 -05:00
John Crepezzi 60f412b7bc Added haste to version control 2011-11-18 18:30:31 -05:00
John Crepezzi 01b622821e Added a command key 2011-11-18 18:17:49 -05:00
John Crepezzi a83ae523b4 Catch exceptions 2011-11-18 18:08:04 -05:00
John Crepezzi 83b8f3f52d Generalize store 2011-11-18 18:04:24 -05:00
John Crepezzi fec02cfead Move storage mechanism to new object 2011-11-18 17:54:57 -05:00
John Crepezzi b173cdd144 preparse static elements rather than fs'ing them 2011-11-18 17:36:35 -05:00
John Crepezzi 0fe0306caa Logger configuration 2011-11-18 17:26:25 -05:00
John Crepezzi a6bd69f20a Rename to haste 2011-11-18 17:24:15 -05:00
John Crepezzi fe68e42b90 Don't save blank docs 2011-11-18 17:21:31 -05:00
John Crepezzi 4a435a4be5 Cleanup todo 2011-11-18 17:14:44 -05:00
John Crepezzi f48cc45928 Cleanup and remove TODO that is done 2011-11-18 17:14:03 -05:00
John Crepezzi 7709e12500 Added FS backed 2011-11-18 17:12:28 -05:00
John Crepezzi 93435715f2 Fix loggin 2011-11-18 16:58:21 -05:00
John Crepezzi 6bdd7d7fc5 Host and port made configurable 2011-11-18 16:57:23 -05:00
John Crepezzi b159817a27 Added configuration and made key length configurable 2011-11-18 16:54:16 -05:00
John Crepezzi 0eed33f42f 400 should be 404 2011-11-18 16:50:23 -05:00
John Crepezzi cf384cd0fd Added random keys 2011-11-18 16:45:48 -05:00
John Crepezzi f935ac56c2 Nicer page titles 2011-11-18 16:42:05 -05:00
John Crepezzi d69839b2fb Push state for new documents fixed 2011-11-18 16:37:38 -05:00
John Crepezzi 3acc2eb17d Catch an error 2011-11-18 16:28:09 -05:00
John Crepezzi 7b2d0f549d Remove some finished TODOs 2011-11-18 16:25:53 -05:00
John Crepezzi 8a8b438163 Change uuid to key 2011-11-18 16:25:18 -05:00
John Crepezzi 6597dba36d Handle push state entirely 2011-11-18 16:22:00 -05:00
John Crepezzi 4f00d3c71a Remove url from static_handler.js 2011-11-18 16:00:05 -05:00
John Crepezzi 44d54174ed Push state on doc change 2011-11-18 15:55:01 -05:00
John Crepezzi 13e497993f Separate logic into proper places 2011-11-18 15:51:38 -05:00
John Crepezzi 6bac45efe2 More work on the server 2011-11-18 15:44:28 -05:00
John Crepezzi b35c89a472 Added duplicate functionality 2011-11-18 15:18:38 -05:00
John Crepezzi f22f347d43 Light refactor 2011-11-18 10:49:38 -05:00
John Crepezzi 7756e38595 Document saving almost working 2011-11-18 10:49:00 -05:00
John Crepezzi 7cc30e4b69 ctrl-n for new documents 2011-11-18 10:19:44 -05:00
John Crepezzi c5a551f770 Move to static, rewrite client-JS 2011-11-18 10:17:41 -05:00
John Crepezzi 5b874e3456 Upgrade jquery to remove warnings 2011-11-17 22:47:56 -05:00
John Crepezzi c90561da8e Remove finished todo 2011-11-17 22:45:41 -05:00
John Crepezzi 90161e780d Turn off spellcheck 2011-11-17 22:45:25 -05:00
John Crepezzi 9d0b0c9f21 Things working 2011-11-17 22:44:48 -05:00
40 changed files with 2537 additions and 385 deletions
+2
View File
@@ -0,0 +1,2 @@
**/*.min.js
config.js
+25
View File
@@ -0,0 +1,25 @@
{
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
}
+6
View File
@@ -0,0 +1,6 @@
npm-debug.log
node_modules
*.swp
*.swo
data
*.DS_Store
+1
View File
@@ -0,0 +1 @@
web: node server.js
+233
View File
@@ -0,0 +1,233 @@
# Haste
Haste is an open-source pastebin software written in node.js, which is easily
installable in any network. It can be backed by either redis or filesystem,
and has a very easy adapter interface for other stores. A publicly available
version can be found at [hastebin.com](http://hastebin.com)
Major design objectives:
* Be really pretty
* Be really simple
* Be easy to set up and use
Haste works really well with a little utility called
[haste-client](https://github.com/seejohnrun/haste-client), allowing you
to do things like:
`cat something | haste`
which will output a URL to share containing the contents of `cat something`'s
STDOUT. Check the README there for more details and usages.
## Tested Browsers
* Firefox 8
* Chrome 17
* Safari 5.3
## Installation
1. Download the package, and expand it
2. Explore the settings inside of config.js, but the defaults should be good
3. `npm install`
4. `npm start`
## Settings
* `host` - the host the server runs on (default localhost)
* `port` - the port the server runs on (default 7777)
* `keyLength` - the length of the keys to user (default 10)
* `maxLength` - maximum length of a paste (default 400000)
* `staticMaxAge` - max age for static assets (86400)
* `recompressStaticAssets` - whether or not to compile static js assets (true)
* `documents` - static documents to serve (ex: http://hastebin.com/about.com)
in addition to static assets. These will never expire.
* `storage` - storage options (see below)
* `logging` - logging preferences
* `keyGenerator` - key generator options (see below)
* `rateLimits` - settings for rate limiting (see below)
## Rate Limiting
When present, the `rateLimits` option enables built-in rate limiting courtesy
of `connect-ratelimit`. Any of the options supported by that library can be
used and set in `config.json`.
See the README for [connect-ratelimit](https://github.com/dharmafly/connect-ratelimit)
for more information!
## Key Generation
### Phonetic
Attempts to generate phonetic keys, similar to `pwgen`
``` json
{
"type": "phonetic"
}
```
### Random
Generates a random key
``` json
{
"type": "random",
"keyspace": "abcdef"
}
```
The _optional_ keySpace argument is a string of acceptable characters
for the key.
## Storage
### File
To use file storage (the default) change the storage section in `config.js` to
something like:
``` json
{
"path": "./data",
"type": "file"
}
```
where `path` represents where you want the files stored.
File storage currently does not support paste expiration, you can follow [#191](https://github.com/seejohnrun/haste-server/issues/191) for status updates.
### Redis
To use redis storage you must install the `redis` package in npm, and have
`redis-server` running on the machine.
`npm install redis`
Once you've done that, your config section should look like:
``` json
{
"type": "redis",
"host": "localhost",
"port": 6379,
"db": 2
}
```
You can also set an `expire` option to the number of seconds to expire keys in.
This is off by default, but will constantly kick back expirations on each view
or post.
All of which are optional except `type` with very logical default values.
If your Redis server is configured for password authentification, use the `password` field.
### Postgres
To use postgres storage you must install the `pg` package in npm
`npm install pg`
Once you've done that, your config section should look like:
``` json
{
"type": "postgres",
"connectionUrl": "postgres://user:password@host:5432/database"
}
```
You can also just set the environment variable for `DATABASE_URL` to your database connection url.
You will have to manually add a table to your postgres database:
`create table entries (id serial primary key, key varchar(255) not null, value text not null, expiration int, unique(key));`
You can also set an `expire` option to the number of seconds to expire keys in.
This is off by default, but will constantly kick back expirations on each view
or post.
All of which are optional except `type` with very logical default values.
### Memcached
To use memcache storage you must install the `memcached` package via npm
`npm install memcached`
Once you've done that, your config section should look like:
``` json
{
"type": "memcached",
"host": "127.0.0.1",
"port": 11211
}
```
You can also set an `expire` option to the number of seconds to expire keys in.
This behaves just like the redis expirations, but does not push expirations
forward on GETs.
All of which are optional except `type` with very logical default values.
### RethinkDB
To use the RethinkDB storage system, you must install the `rethinkdbdash` package via npm
`npm install rethinkdbdash`
Once you've done that, your config section should look like this:
``` json
{
"type": "rethinkdb",
"host": "127.0.0.1",
"port": 28015,
"db": "haste"
}
```
In order for this to work, the database must be pre-created before the script is ran.
Also, you must create an `uploads` table, which will store all the data for uploads.
You can optionally add the `user` and `password` properties to use a user system.
## Author
John Crepezzi <john.crepezzi@gmail.com>
## License
(The MIT License)
Copyright © 2011-2012 John Crepezzi
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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
### Other components:
* jQuery: MIT/GPL license
* highlight.js: Copyright © 2006, Ivan Sagalaev
* highlightjs-coffeescript: WTFPL - Copyright © 2011, Dmytrii Nagirniak
+36
View File
@@ -0,0 +1,36 @@
# Haste
Sharing code is a good thing, and it should be _really_ easy to do it.
A lot of times, I want to show you something I'm seeing - and that's where we
use pastebins.
Haste is the prettiest, easiest to use pastebin ever made.
## Basic Usage
Type what you want me to see, click "Save", and then copy the URL. Send that
URL to someone and they'll see what you see.
To make a new entry, click "New" (or type 'control + n')
## From the Console
[bin-client](git.webionite.com/ceda_ei/bin-client)
Add the following to your bashrc/zshrc
```
export MKR_BIN='https://bin.webionite.com/'
export HASTEBIN=1
```
## Open Source
Haste can easily be installed behind your network, and it's all open source!
* [haste-client](https://github.com/seejohnrun/haste-client)
* [haste-server](https://github.com/seejohnrun/haste-server)
## Author
Code by John Crepezzi <john.crepezzi@gmail.com>
Key Design by Brian Dawson <bridawson@gmail.com>
+46
View File
@@ -0,0 +1,46 @@
{
"host": "0.0.0.0",
"port": 7777,
"keyLength": 10,
"maxLength": 400000,
"staticMaxAge": 86400,
"recompressStaticAssets": true,
"logging": [
{
"level": "verbose",
"type": "Console",
"colorize": true
}
],
"keyGenerator": {
"type": "phonetic"
},
"rateLimits": {
"categories": {
"normal": {
"totalRequests": 500,
"every": 60000
}
}
},
"storage": {
"type": "memcached",
"host": "127.0.0.1",
"port": 11211,
"expire": 2592000
},
"documents": {
"about": "./about.md"
}
}
-43
View File
@@ -1,43 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Haste-server by seejohnrun</title>
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1>Haste-server</h1>
<p>open source pastebin written in node.js</p>
<p class="view"><a href="https://github.com/seejohnrun/haste-server">View the Project on GitHub <small>seejohnrun/haste-server</small></a></p>
<ul>
<li><a href="https://github.com/seejohnrun/haste-server/zipball/master">Download <strong>ZIP File</strong></a></li>
<li><a href="https://github.com/seejohnrun/haste-server/tarball/master">Download <strong>TAR Ball</strong></a></li>
<li><a href="https://github.com/seejohnrun/haste-server">Fork On <strong>GitHub</strong></a></li>
</ul>
</header>
<section>
<h1>Pastebin</h1>
<p>haste-server is an open source pastebin. You can see an example at <a href="http://hastebin.com">hastebin.com</a>, and it's easy to install locally.</p>
<h2>GitHub</h2>
<p>Check out the project on <a href="https://github.com/seejohnrun/haste-server">github</a></p>
</section>
<footer>
<p>This project is maintained by <a href="https://github.com/seejohnrun">seejohnrun</a></p>
<p><small>Hosted on GitHub Pages &mdash; Theme by <a href="https://github.com/orderedlist">orderedlist</a></small></p>
</footer>
</div>
<script src="javascripts/scale.fix.js"></script>
</body>
</html>
-17
View File
@@ -1,17 +0,0 @@
var metas = document.getElementsByTagName('meta');
var i;
if (navigator.userAgent.match(/iPhone/i)) {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport") {
metas[i].content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
}
}
document.addEventListener("gesturestart", gestureStart, false);
}
function gestureStart() {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport") {
metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
}
}
}
+133
View File
@@ -0,0 +1,133 @@
var winston = require('winston');
var Busboy = require('busboy');
// For handling serving stored documents
var DocumentHandler = function(options) {
if (!options) {
options = {};
}
this.keyLength = options.keyLength || DocumentHandler.defaultKeyLength;
this.maxLength = options.maxLength; // none by default
this.store = options.store;
this.keyGenerator = options.keyGenerator;
};
DocumentHandler.defaultKeyLength = 10;
// Handle retrieving a document
DocumentHandler.prototype.handleGet = function(key, response, skipExpire) {
this.store.get(key, function(ret) {
if (ret) {
winston.verbose('retrieved document', { key: key });
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify({ data: ret, key: key }));
}
else {
winston.warn('document not found', { key: key });
response.writeHead(404, { 'content-type': 'application/json' });
response.end(JSON.stringify({ message: 'Document not found.' }));
}
}, skipExpire);
};
// Handle retrieving the raw version of a document
DocumentHandler.prototype.handleRawGet = function(key, response, skipExpire) {
this.store.get(key, function(ret) {
if (ret) {
winston.verbose('retrieved raw document', { key: key });
response.writeHead(200, { 'content-type': 'text/plain; charset=UTF-8' });
response.end(ret);
}
else {
winston.warn('raw document not found', { key: key });
response.writeHead(404, { 'content-type': 'application/json' });
response.end(JSON.stringify({ message: 'Document not found.' }));
}
}, skipExpire);
};
// Handle adding a new Document
DocumentHandler.prototype.handlePost = function (request, response) {
var _this = this;
var buffer = '';
var cancelled = false;
// What to do when done
var onSuccess = function () {
// Check length
if (_this.maxLength && buffer.length > _this.maxLength) {
cancelled = true;
winston.warn('document >maxLength', { maxLength: _this.maxLength });
response.writeHead(400, { 'content-type': 'application/json' });
response.end(
JSON.stringify({ message: 'Document exceeds maximum length.' })
);
return;
}
// And then save if we should
_this.chooseKey(function (key) {
_this.store.set(key, buffer, function (res) {
if (res) {
winston.verbose('added document', { key: key });
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify({ key: key }));
}
else {
winston.verbose('error adding document');
response.writeHead(500, { 'content-type': 'application/json' });
response.end(JSON.stringify({ message: 'Error adding document.' }));
}
});
});
};
// If we should, parse a form to grab the data
var ct = request.headers['content-type'];
if (ct && ct.split(';')[0] === 'multipart/form-data') {
var busboy = new Busboy({ headers: request.headers });
busboy.on('field', function (fieldname, val) {
if (fieldname === 'data') {
buffer = val;
}
});
busboy.on('finish', function () {
onSuccess();
});
request.pipe(busboy);
// Otherwise, use our own and just grab flat data from POST body
} else {
request.on('data', function (data) {
buffer += data.toString();
});
request.on('end', function () {
if (cancelled) { return; }
onSuccess();
});
request.on('error', function (error) {
winston.error('connection error: ' + error.message);
response.writeHead(500, { 'content-type': 'application/json' });
response.end(JSON.stringify({ message: 'Connection error.' }));
cancelled = true;
});
}
};
// Keep choosing keys until one isn't taken
DocumentHandler.prototype.chooseKey = function(callback) {
var key = this.acceptableKey();
var _this = this;
this.store.get(key, function(ret) {
if (ret) {
_this.chooseKey(callback);
} else {
callback(key);
}
}, true); // Don't bump expirations when key searching
};
DocumentHandler.prototype.acceptableKey = function() {
return this.keyGenerator.createKey(this.keyLength);
};
module.exports = DocumentHandler;
+63
View File
@@ -0,0 +1,63 @@
var fs = require('fs');
var crypto = require('crypto');
var winston = require('winston');
// For storing in files
// options[type] = file
// options[path] - Where to store
var FileDocumentStore = function(options) {
this.basePath = options.path || './data';
this.expire = options.expire;
};
// Generate md5 of a string
FileDocumentStore.md5 = function(str) {
var md5sum = crypto.createHash('md5');
md5sum.update(str);
return md5sum.digest('hex');
};
// Save data in a file, key as md5 - since we don't know what we could
// be passed here
FileDocumentStore.prototype.set = function(key, data, callback, skipExpire) {
try {
var _this = this;
fs.mkdir(this.basePath, '700', function() {
var fn = _this.basePath + '/' + FileDocumentStore.md5(key);
fs.writeFile(fn, data, 'utf8', function(err) {
if (err) {
callback(false);
}
else {
callback(true);
if (_this.expire && !skipExpire) {
winston.warn('file store cannot set expirations on keys');
}
}
});
});
} catch(err) {
callback(false);
}
};
// Get data from a file from key
FileDocumentStore.prototype.get = function(key, callback, skipExpire) {
var _this = this;
var fn = this.basePath + '/' + FileDocumentStore.md5(key);
fs.readFile(fn, 'utf8', function(err, data) {
if (err) {
callback(false);
}
else {
callback(data);
if (_this.expire && !skipExpire) {
winston.warn('file store cannot set expirations on keys');
}
}
});
};
module.exports = FileDocumentStore;
+52
View File
@@ -0,0 +1,52 @@
const memcached = require('memcached');
const winston = require('winston');
class MemcachedDocumentStore {
// Create a new store with options
constructor(options) {
this.expire = options.expire;
const host = options.host || '127.0.0.1';
const port = options.port || 11211;
const url = `${host}:${port}`;
this.connect(url);
}
// Create a connection
connect(url) {
this.client = new memcached(url);
winston.info(`connecting to memcached on ${url}`);
this.client.on('failure', function(error) {
winston.info('error connecting to memcached', {error});
});
}
// Save file in a key
set(key, data, callback, skipExpire) {
this.client.set(key, data, skipExpire ? 0 : this.expire, (error) => {
callback(!error);
});
}
// Get a file from a key
get(key, callback, skipExpire) {
this.client.get(key, (error, data) => {
callback(error ? false : data);
// Update the key so that the expiration is pushed forward
if (!skipExpire) {
this.set(key, data, (updateSucceeded) => {
if (!updateSucceeded) {
winston.error('failed to update expiration on GET', {key});
}
}, skipExpire);
}
});
}
}
module.exports = MemcachedDocumentStore;
+79
View File
@@ -0,0 +1,79 @@
/*global require,module,process*/
var postgres = require('pg');
var winston = require('winston');
// create table entries (id serial primary key, key varchar(255) not null, value text not null, expiration int, unique(key));
// A postgres document store
var PostgresDocumentStore = function (options) {
this.expireJS = options.expire;
this.connectionUrl = process.env.DATABASE_URL || options.connectionUrl;
};
PostgresDocumentStore.prototype = {
// Set a given key
set: function (key, data, callback, skipExpire) {
var now = Math.floor(new Date().getTime() / 1000);
var that = this;
this.safeConnect(function (err, client, done) {
if (err) { return callback(false); }
client.query('INSERT INTO entries (key, value, expiration) VALUES ($1, $2, $3)', [
key,
data,
that.expireJS && !skipExpire ? that.expireJS + now : null
], function (err) {
if (err) {
winston.error('error persisting value to postgres', { error: err });
return callback(false);
}
callback(true);
done();
});
});
},
// Get a given key's data
get: function (key, callback, skipExpire) {
var now = Math.floor(new Date().getTime() / 1000);
var that = this;
this.safeConnect(function (err, client, done) {
if (err) { return callback(false); }
client.query('SELECT id,value,expiration from entries where KEY = $1 and (expiration IS NULL or expiration > $2)', [key, now], function (err, result) {
if (err) {
winston.error('error retrieving value from postgres', { error: err });
return callback(false);
}
callback(result.rows.length ? result.rows[0].value : false);
if (result.rows.length && that.expireJS && !skipExpire) {
client.query('UPDATE entries SET expiration = $1 WHERE ID = $2', [
that.expireJS + now,
result.rows[0].id
], function (err) {
if (!err) {
done();
}
});
} else {
done();
}
});
});
},
// A connection wrapper
safeConnect: function (callback) {
postgres.connect(this.connectionUrl, function (err, client, done) {
if (err) {
winston.error('error connecting to postgres', { error: err });
callback(err);
} else {
callback(undefined, client, done);
}
});
}
};
module.exports = PostgresDocumentStore;
+89
View File
@@ -0,0 +1,89 @@
var redis = require('redis');
var winston = require('winston');
// For storing in redis
// options[type] = redis
// options[host] - The host to connect to (default localhost)
// options[port] - The port to connect to (default 5379)
// options[db] - The db to use (default 0)
// options[expire] - The time to live for each key set (default never)
var RedisDocumentStore = function(options, client) {
this.expire = options.expire;
if (client) {
winston.info('using predefined redis client');
RedisDocumentStore.client = client;
} else if (!RedisDocumentStore.client) {
winston.info('configuring redis');
RedisDocumentStore.connect(options);
}
};
// Create a connection according to config
RedisDocumentStore.connect = function(options) {
var host = options.host || '127.0.0.1';
var port = options.port || 6379;
var index = options.db || 0;
RedisDocumentStore.client = redis.createClient(port, host);
// authenticate if password is provided
if (options.password) {
RedisDocumentStore.client.auth(options.password);
}
RedisDocumentStore.client.on('error', function(err) {
winston.error('redis disconnected', err);
});
RedisDocumentStore.client.select(index, function(err) {
if (err) {
winston.error(
'error connecting to redis index ' + index,
{ error: err }
);
process.exit(1);
}
else {
winston.info('connected to redis on ' + host + ':' + port + '/' + index);
}
});
};
// Save file in a key
RedisDocumentStore.prototype.set = function(key, data, callback, skipExpire) {
var _this = this;
RedisDocumentStore.client.set(key, data, function(err) {
if (err) {
callback(false);
}
else {
if (!skipExpire) {
_this.setExpiration(key);
}
callback(true);
}
});
};
// Expire a key in expire time if set
RedisDocumentStore.prototype.setExpiration = function(key) {
if (this.expire) {
RedisDocumentStore.client.expire(key, this.expire, function(err) {
if (err) {
winston.error('failed to set expiry on key: ' + key);
}
});
}
};
// Get a file from a key
RedisDocumentStore.prototype.get = function(key, callback, skipExpire) {
var _this = this;
RedisDocumentStore.client.get(key, function(err, reply) {
if (!err && !skipExpire) {
_this.setExpiration(key);
}
callback(err ? false : reply);
});
};
module.exports = RedisDocumentStore;
+46
View File
@@ -0,0 +1,46 @@
const crypto = require('crypto');
const rethink = require('rethinkdbdash');
const winston = require('winston');
const md5 = (str) => {
const md5sum = crypto.createHash('md5');
md5sum.update(str);
return md5sum.digest('hex');
};
class RethinkDBStore {
constructor(options) {
this.client = rethink({
silent: true,
host: options.host || '127.0.0.1',
port: options.port || 28015,
db: options.db || 'haste',
user: options.user || 'admin',
password: options.password || ''
});
}
set(key, data, callback) {
this.client.table('uploads').insert({ id: md5(key), data: data }).run((error) => {
if (error) {
callback(false);
winston.error('failed to insert to table', error);
return;
}
callback(true);
});
}
get(key, callback) {
this.client.table('uploads').get(md5(key)).run((error, result) => {
if (error || !result) {
callback(false);
if (error) winston.error('failed to insert to table', error);
return;
}
callback(result.data);
});
}
}
module.exports = RethinkDBStore;
+32
View File
@@ -0,0 +1,32 @@
const fs = require('fs');
module.exports = class DictionaryGenerator {
constructor(options, readyCallback) {
// Check options format
if (!options) throw Error('No options passed to generator');
if (!options.path) throw Error('No dictionary path specified in options');
// Load dictionary
fs.readFile(options.path, 'utf8', (err, data) => {
if (err) throw err;
this.dictionary = data.split(/[\n\r]+/);
if (readyCallback) readyCallback();
});
}
// Generates a dictionary-based key, of keyLength words
createKey(keyLength) {
let text = '';
for (let i = 0; i < keyLength; i++) {
const index = Math.floor(Math.random() * this.dictionary.length);
text += this.dictionary[index];
}
return text;
}
};
+27
View File
@@ -0,0 +1,27 @@
// Draws inspiration from pwgen and http://tools.arantius.com/password
const randOf = (collection) => {
return () => {
return collection[Math.floor(Math.random() * collection.length)];
};
};
// Helper methods to get an random vowel or consonant
const randVowel = randOf('aeiou');
const randConsonant = randOf('bcdfghjklmnpqrstvwxyz');
module.exports = class PhoneticKeyGenerator {
// Generate a phonetic key of alternating consonant & vowel
createKey(keyLength) {
let text = '';
const start = Math.round(Math.random());
for (let i = 0; i < keyLength; i++) {
text += (i % 2 == start) ? randConsonant() : randVowel();
}
return text;
}
};
+20
View File
@@ -0,0 +1,20 @@
module.exports = class RandomKeyGenerator {
// Initialize a new generator with the given keySpace
constructor(options = {}) {
this.keyspace = options.keyspace || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
}
// Generate a key of the given length
createKey(keyLength) {
var text = '';
for (var i = 0; i < keyLength; i++) {
const index = Math.floor(Math.random() * this.keyspace.length);
text += this.keyspace.charAt(index);
}
return text;
}
};
+548
View File
@@ -0,0 +1,548 @@
{
"name": "haste",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"async": {
"version": "0.1.22",
"resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz",
"integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE="
},
"async-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-cache/-/async-cache-1.0.0.tgz",
"integrity": "sha1-yH9tgMcrOU7g+QYe3rJNjEtiKto=",
"requires": {
"lru-cache": "2.3.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"bl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz",
"integrity": "sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=",
"requires": {
"readable-stream": "2.0.6"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"readable-stream": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"string_decoder": "0.10.31",
"util-deprecate": "1.0.2"
}
}
}
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
"dev": true,
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"browser-stdout": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
"integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
"dev": true
},
"buffer-writer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.0.tgz",
"integrity": "sha1-bCnDst6gyeRVofJhoZmkigT4iwg="
},
"busboy": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.4.tgz",
"integrity": "sha1-GXfpbh7ohGSWUevfVIypAHWLp/M=",
"requires": {
"dicer": "0.2.3",
"readable-stream": "1.1.14"
}
},
"colors": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
"integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w="
},
"commander": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
"dev": true,
"requires": {
"graceful-readlink": "1.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"connect": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.4.1.tgz",
"integrity": "sha1-ohNh0/QJnvdhzabcSpc7seuwo00=",
"requires": {
"debug": "2.2.0",
"finalhandler": "0.4.1",
"parseurl": "1.3.1",
"utils-merge": "1.0.0"
}
},
"connect-ratelimit": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/connect-ratelimit/-/connect-ratelimit-0.0.7.tgz",
"integrity": "sha1-5uCclQZJ6ElJnKsYcKQVoH9zFWg="
},
"connect-route": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/connect-route/-/connect-route-0.1.5.tgz",
"integrity": "sha1-48IYMZ0uiKiprgsOD+Cacpw5dEo="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cycle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
"integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
},
"debug": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
"requires": {
"ms": "0.7.1"
}
},
"dicer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.3.tgz",
"integrity": "sha1-8AKBGJpVwjUe+ASQpP6fssWcSTk=",
"requires": {
"readable-stream": "1.1.14",
"streamsearch": "0.1.2"
}
},
"diff": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
"integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=",
"dev": true
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"eyes": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
},
"fd": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/fd/-/fd-0.0.2.tgz",
"integrity": "sha1-4O2yvXqIzIbdnxY5HLqDJBj9h+4="
},
"finalhandler": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.1.tgz",
"integrity": "sha1-haF8bFmpRxfSYtYSMNSw6+PUoU0=",
"requires": {
"debug": "2.2.0",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"unpipe": "1.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"generic-pool": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.1.1.tgz",
"integrity": "sha1-rwTcLDJc/Ll1Aj+lK/zpYXp0Nf0="
},
"glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
"integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
"dev": true,
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"optional": true
},
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"dev": true
},
"growl": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz",
"integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=",
"dev": true
},
"has-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
"integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
"dev": true
},
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"lru-cache": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.3.1.tgz",
"integrity": "sha1-s632s9hW6VTiw5DmzvIggSRaU9Y="
},
"mime": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz",
"integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "1.1.8"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
}
},
"mocha": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz",
"integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==",
"dev": true,
"requires": {
"browser-stdout": "1.3.0",
"commander": "2.9.0",
"debug": "2.2.0",
"diff": "3.2.0",
"escape-string-regexp": "1.0.5",
"glob": "7.1.1",
"growl": "1.9.2",
"he": "1.1.1",
"mkdirp": "0.5.1",
"supports-color": "3.1.2"
}
},
"ms": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
"integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1.0.2"
}
},
"packet-reader": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.2.0.tgz",
"integrity": "sha1-gZ300BC4LV6lZx+KGjrPA5vNdwA="
},
"parseurl": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz",
"integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"pg": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/pg/-/pg-4.1.1.tgz",
"integrity": "sha1-mEgKz8089qP5Yhyl1FiUFVgqVzI=",
"requires": {
"buffer-writer": "1.0.0",
"generic-pool": "2.1.1",
"packet-reader": "0.2.0",
"pg-connection-string": "0.1.3",
"pg-types": "1.6.0",
"pgpass": "0.0.3",
"semver": "4.3.6"
}
},
"pg-connection-string": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
"integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc="
},
"pg-types": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.6.0.tgz",
"integrity": "sha1-OHKg8ZkUMCVJf07ipl/a8A1+qLM="
},
"pgpass": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-0.0.3.tgz",
"integrity": "sha1-EuZ+NDsxicLzEgbrycwL7//PkUA=",
"requires": {
"split": "0.3.3"
}
},
"pkginfo": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz",
"integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "0.0.1",
"string_decoder": "0.10.31"
}
},
"redis": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/redis/-/redis-0.8.1.tgz",
"integrity": "sha1-FZ8hMFmaL3GeRLA/C0t2EvmS/LI="
},
"redis-url": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/redis-url/-/redis-url-0.1.0.tgz",
"integrity": "sha1-TaXlsYG2wMrW4aVcf1Co5u53ebs=",
"requires": {
"redis": "0.8.1"
}
},
"request": {
"version": "2.9.203",
"resolved": "https://registry.npmjs.org/request/-/request-2.9.203.tgz",
"integrity": "sha1-bBcRpUB/uUoRQhlWPkQUW8v0cjo="
},
"semver": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"split": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
"integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
"requires": {
"through": "2.3.8"
}
},
"st": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/st/-/st-1.1.0.tgz",
"integrity": "sha1-c7ltsLdkTZp4zjg0o+T37G6Hz3Y=",
"requires": {
"async-cache": "1.0.0",
"bl": "1.0.3",
"fd": "0.0.2",
"graceful-fs": "4.1.11",
"mime": "1.3.6",
"negotiator": "0.6.1"
}
},
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"supports-color": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
"integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=",
"dev": true,
"requires": {
"has-flag": "1.0.0"
}
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"uglify-js": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.6.tgz",
"integrity": "sha512-/rseyxEKEVMBo8279lqpoJgD6C/i/CIi+9TJDvWmb+Xo6mqMKwjA8Io3IMHlcXQzj99feR6zrN8m3wqqvm/nYA==",
"requires": {
"commander": "2.11.0",
"source-map": "0.6.1"
},
"dependencies": {
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
}
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"utils-merge": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
"integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
},
"winston": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/winston/-/winston-0.6.2.tgz",
"integrity": "sha1-QUT+JYbNwZphK/jANVkBMskGS9I=",
"requires": {
"async": "0.1.22",
"colors": "0.6.2",
"cycle": "1.0.3",
"eyes": "0.1.8",
"pkginfo": "0.2.3",
"request": "2.9.203",
"stack-trace": "0.0.10"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
}
}
}
+51
View File
@@ -0,0 +1,51 @@
{
"name": "haste",
"version": "0.1.0",
"private": true,
"description": "Private Pastebin Server",
"keywords": [
"paste",
"pastebin"
],
"author": {
"name": "John Crepezzi",
"email": "john.crepezzi@gmail.com",
"url": "http://seejohncode.com/"
},
"main": "haste",
"dependencies": {
"connect-ratelimit": "0.0.7",
"connect-route": "0.1.5",
"connect": "3.4.1",
"st": "1.1.0",
"winston": "0.6.2",
"redis-url": "0.1.0",
"redis": "0.8.1",
"uglify-js": "3.1.6",
"busboy": "0.2.4",
"pg": "4.1.1"
},
"devDependencies": {
"mocha": "^4.0.1"
},
"bundledDependencies": [],
"engines": {
"node": "8.1.4",
"npm": "5.2.0"
},
"bin": {
"haste-server": "./server.js"
},
"files": [
"server.js",
"lib",
"static"
],
"directories": {
"lib": "./lib"
},
"scripts": {
"start": "node server.js",
"test": "mocha --recursive"
}
}
-1
View File
@@ -1 +0,0 @@
{"name":"Haste-server","body":"# Pastebin\r\n\r\nhaste-server is an open source pastebin. You can see an example at [hastebin.com](http://hastebin.com), and it's easy to install locally.\r\n\r\n## GitHub\r\n\r\nCheck out the project on [github](https://github.com/seejohnrun/haste-server)","tagline":"open source pastebin written in node.js","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
+159
View File
@@ -0,0 +1,159 @@
// vim: set ts=2 sw=2 sts=2 et:
var http = require('http');
var fs = require('fs');
var uglify = require('uglify-js');
var winston = require('winston');
var connect = require('connect');
var route = require('connect-route');
var connect_st = require('st');
var connect_rate_limit = require('connect-ratelimit');
var DocumentHandler = require('./lib/document_handler');
// Load the configuration and set some defaults
var config = JSON.parse(fs.readFileSync('./config.js', 'utf8'));
config.port = process.env.PORT || config.port || 7777;
config.host = process.env.HOST || config.host || 'localhost';
// Set up the logger
if (config.logging) {
try {
winston.remove(winston.transports.Console);
} catch(e) {
/* was not present */
}
var detail, type;
for (var i = 0; i < config.logging.length; i++) {
detail = config.logging[i];
type = detail.type;
delete detail.type;
winston.add(winston.transports[type], detail);
}
}
// build the store from the config on-demand - so that we don't load it
// for statics
if (!config.storage) {
config.storage = { type: 'file' };
}
if (!config.storage.type) {
config.storage.type = 'file';
}
var Store, preferredStore;
if (process.env.REDISTOGO_URL && config.storage.type === 'redis') {
var redisClient = require('redis-url').connect(process.env.REDISTOGO_URL);
Store = require('./lib/document_stores/redis');
preferredStore = new Store(config.storage, redisClient);
}
else {
Store = require('./lib/document_stores/' + config.storage.type);
preferredStore = new Store(config.storage);
}
// Compress the static javascript assets
if (config.recompressStaticAssets) {
var list = fs.readdirSync('./static');
for (var j = 0; j < list.length; j++) {
var item = list[j];
if ((item.indexOf('.js') === item.length - 3) && (item.indexOf('.min.js') === -1)) {
var dest = item.substring(0, item.length - 3) + '.min' + item.substring(item.length - 3);
var orig_code = fs.readFileSync('./static/' + item, 'utf8');
fs.writeFileSync('./static/' + dest, uglify.minify(orig_code).code, 'utf8');
winston.info('compressed ' + item + ' into ' + dest);
}
}
}
// Send the static documents into the preferred store, skipping expirations
var path, data;
for (var name in config.documents) {
path = config.documents[name];
data = fs.readFileSync(path, 'utf8');
winston.info('loading static document', { name: name, path: path });
if (data) {
preferredStore.set(name, data, function(cb) {
winston.debug('loaded static document', { success: cb });
}, true);
}
else {
winston.warn('failed to load static document', { name: name, path: path });
}
}
// Pick up a key generator
var pwOptions = config.keyGenerator || {};
pwOptions.type = pwOptions.type || 'random';
var gen = require('./lib/key_generators/' + pwOptions.type);
var keyGenerator = new gen(pwOptions);
// Configure the document handler
var documentHandler = new DocumentHandler({
store: preferredStore,
maxLength: config.maxLength,
keyLength: config.keyLength,
keyGenerator: keyGenerator
});
var app = connect();
// Rate limit all requests
if (config.rateLimits) {
config.rateLimits.end = true;
app.use(connect_rate_limit(config.rateLimits));
}
function raw(request, response) {
var key = request.params.id.split('.')[0];
var skipExpire = !!config.documents[key];
return documentHandler.handleRawGet(key, response, skipExpire);
}
// first look at API calls
app.use(route(function(router) {
// get raw documents - support getting with extension
router.get('/raw/:id', raw);
router.get('/:id/raw', raw);
// add documents
router.post('/documents', function(request, response) {
return documentHandler.handlePost(request, response);
});
// get documents
router.get('/documents/:id', function(request, response) {
var key = request.params.id.split('.')[0];
var skipExpire = !!config.documents[key];
return documentHandler.handleGet(key, response, skipExpire);
});
}));
// Otherwise, try to match static files
app.use(connect_st({
path: __dirname + '/static',
content: { maxAge: config.staticMaxAge },
passthrough: true,
index: false
}));
// Then we can loop back - and everything else should be a token,
// so route it back to /
app.use(route(function(router) {
router.get('/:id', function(request, _response, next) {
request.sturl = '/';
next();
});
}));
// And match index
app.use(connect_st({
path: __dirname + '/static',
content: { maxAge: config.staticMaxAge },
index: 'index.html'
}));
http.createServer(app).listen(config.port, config.host);
winston.info('listening on ' + config.host + ':' + config.port);
+171
View File
@@ -0,0 +1,171 @@
body {
background: #002B36;
padding: 20px 50px;
margin: 0px;
}
/* textarea */
textarea {
background: transparent;
border: 0px;
color: #fff;
padding: 0px;
width: 100%;
height: 100%;
font-family: monospace;
outline: none;
resize: none;
font-size: 13px;
}
/* the line numbers */
#linenos {
color: #7d7d7d;
z-index: -1000;
position: absolute;
top: 20px;
left: 0px;
width: 30px; /* 30 to get 20 away from box */
font-size: 13px;
font-family: monospace;
text-align: right;
}
/* code box when locked */
#box {
padding: 0px;
margin: 0px;
width: 100%;
border: 0px;
outline: none;
font-size: 13px;
overflow: inherit;
}
#box code {
padding: 0px;
background: transparent !important; /* don't hide hastebox */
}
/* key */
#key {
position: fixed;
top: 0px;
right: 0px;
z-index: +1000; /* watch out */
}
#box1 {
padding: 5px;
text-align: center;
background: #00222b;
}
#box2 {
background: #08323c;
font-size: 0px;
padding: 0px 5px;
}
#box1 a.logo, #box1 a.logo:visited {
display: inline-block;
background: url(logo.png);
width: 126px;
height: 42px;
}
#box1 a.logo:hover {
background-position: 0 bottom;
}
#box2 .function {
background: url(function-icons.png);
width: 32px;
height: 37px;
display: inline-block;
position: relative;
}
#box2 .link embed {
vertical-align: bottom; /* fix for zeroClipboard style */
}
#box2 .function.enabled:hover {
cursor: hand;
cursor: pointer;
}
#pointer {
display: block;
height: 5px;
width: 10px;
background: url(hover-dropdown-tip.png);
bottom: 0px;
position: absolute;
margin: auto;
left: 0px;
right: 0px;
}
#box3, #messages li {
background: #173e48;
font-family: Helvetica, sans-serif;
font-size: 12px;
line-height: 14px;
padding: 10px 15px;
}
#box3 .label, #messages li {
color: #fff;
font-weight: bold;
}
#box3 .shortcut {
color: #c4dce3;
font-weight: normal;
}
#box2 .function.save { background-position: -5px top; }
#box2 .function.enabled.save { background-position: -5px center; }
#box2 .function.enabled.save:hover { background-position: -5px bottom; }
#box2 .function.new { background-position: -42px top; }
#box2 .function.enabled.new { background-position: -42px center; }
#box2 .function.enabled.new:hover { background-position: -42px bottom; }
#box2 .function.duplicate { background-position: -79px top; }
#box2 .function.enabled.duplicate { background-position: -79px center; }
#box2 .function.enabled.duplicate:hover { background-position: -79px bottom; }
#box2 .function.raw { background-position: -116px top; }
#box2 .function.enabled.raw { background-position: -116px center; }
#box2 .function.enabled.raw:hover { background-position: -116px bottom; }
#box2 .function.twitter { background-position: -153px top; }
#box2 .function.enabled.twitter { background-position: -153px center; }
#box2 .function.enabled.twitter:hover { background-position: -153px bottom; }
#box2 .button-picture{ border-width: 0; font-size: inherit; }
#messages {
position:fixed;
top:0px;
right:138px;
margin:0;
padding:0;
width:400px;
}
#messages li {
background:rgba(23,62,72,0.8);
margin:0 auto;
list-style:none;
}
#messages li.error {
background:rgba(102,8,0,0.8);
}
+399
View File
@@ -0,0 +1,399 @@
/* global $, hljs, window, document */
///// represents a single document
var haste_document = function() {
this.locked = false;
};
// Escapes HTML tag characters
haste_document.prototype.htmlEscape = function(s) {
return s
.replace(/&/g, '&amp;')
.replace(/>/g, '&gt;')
.replace(/</g, '&lt;')
.replace(/"/g, '&quot;');
};
// Get this document from the server and lock it here
haste_document.prototype.load = function(key, callback, lang) {
var _this = this;
$.ajax('/documents/' + key, {
type: 'get',
dataType: 'json',
success: function(res) {
_this.locked = true;
_this.key = key;
_this.data = res.data;
try {
var high;
if (lang === 'txt') {
high = { value: _this.htmlEscape(res.data) };
}
else if (lang) {
high = hljs.highlight(lang, res.data);
}
else {
high = hljs.highlightAuto(res.data);
}
} catch(err) {
// failed highlight, fall back on auto
high = hljs.highlightAuto(res.data);
}
callback({
value: high.value,
key: key,
language: high.language || lang,
lineCount: res.data.split('\n').length
});
},
error: function() {
callback(false);
}
});
};
// Save this document to the server and lock it here
haste_document.prototype.save = function(data, callback) {
if (this.locked) {
return false;
}
this.data = data;
var _this = this;
$.ajax('/documents', {
type: 'post',
data: data,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function(res) {
_this.locked = true;
_this.key = res.key;
var high = hljs.highlightAuto(data);
callback(null, {
value: high.value,
key: res.key,
language: high.language,
lineCount: data.split('\n').length
});
},
error: function(res) {
try {
callback($.parseJSON(res.responseText));
}
catch (e) {
callback({message: 'Something went wrong!'});
}
}
});
};
///// represents the paste application
var haste = function(appName, options) {
this.appName = appName;
this.$textarea = $('textarea');
this.$box = $('#box');
this.$code = $('#box code');
this.$linenos = $('#linenos');
this.options = options;
this.configureShortcuts();
this.configureButtons();
// If twitter is disabled, hide the button
if (!options.twitter) {
$('#box2 .twitter').hide();
}
};
// Set the page title - include the appName
haste.prototype.setTitle = function(ext) {
var title = ext ? this.appName + ' - ' + ext : this.appName;
document.title = title;
};
// Show a message box
haste.prototype.showMessage = function(msg, cls) {
var msgBox = $('<li class="'+(cls || 'info')+'">'+msg+'</li>');
$('#messages').prepend(msgBox);
setTimeout(function() {
msgBox.slideUp('fast', function() { $(this).remove(); });
}, 3000);
};
// Show the light key
haste.prototype.lightKey = function() {
this.configureKey(['new', 'save']);
};
// Show the full key
haste.prototype.fullKey = function() {
this.configureKey(['new', 'duplicate', 'twitter', 'raw']);
};
// Set the key up for certain things to be enabled
haste.prototype.configureKey = function(enable) {
var $this, i = 0;
$('#box2 .function').each(function() {
$this = $(this);
for (i = 0; i < enable.length; i++) {
if ($this.hasClass(enable[i])) {
$this.addClass('enabled');
return true;
}
}
$this.removeClass('enabled');
});
};
// Remove the current document (if there is one)
// and set up for a new one
haste.prototype.newDocument = function(hideHistory) {
this.$box.hide();
this.doc = new haste_document();
if (!hideHistory) {
window.history.pushState(null, this.appName, '/');
}
this.setTitle();
this.lightKey();
this.$textarea.val('').show('fast', function() {
this.focus();
});
this.removeLineNumbers();
};
// Map of common extensions
// Note: this list does not need to include anything that IS its extension,
// due to the behavior of lookupTypeByExtension and lookupExtensionByType
// Note: optimized for lookupTypeByExtension
haste.extensionMap = {
rb: 'ruby', py: 'python', pl: 'perl', php: 'php', scala: 'scala', go: 'go',
xml: 'xml', html: 'xml', htm: 'xml', css: 'css', js: 'javascript', vbs: 'vbscript',
lua: 'lua', pas: 'delphi', java: 'java', cpp: 'cpp', cc: 'cpp', m: 'objectivec',
vala: 'vala', sql: 'sql', sm: 'smalltalk', lisp: 'lisp', ini: 'ini',
diff: 'diff', bash: 'bash', sh: 'bash', tex: 'tex', erl: 'erlang', hs: 'haskell',
md: 'markdown', txt: '', coffee: 'coffee', json: 'javascript',
swift: 'swift'
};
// Look up the extension preferred for a type
// If not found, return the type itself - which we'll place as the extension
haste.prototype.lookupExtensionByType = function(type) {
for (var key in haste.extensionMap) {
if (haste.extensionMap[key] === type) return key;
}
return type;
};
// Look up the type for a given extension
// If not found, return the extension - which we'll attempt to use as the type
haste.prototype.lookupTypeByExtension = function(ext) {
return haste.extensionMap[ext] || ext;
};
// Add line numbers to the document
// For the specified number of lines
haste.prototype.addLineNumbers = function(lineCount) {
var h = '';
for (var i = 0; i < lineCount; i++) {
h += (i + 1).toString() + '<br/>';
}
$('#linenos').html(h);
};
// Remove the line numbers
haste.prototype.removeLineNumbers = function() {
$('#linenos').html('&gt;');
};
// Load a document and show it
haste.prototype.loadDocument = function(key) {
// Split the key up
var parts = key.split('.', 2);
// Ask for what we want
var _this = this;
_this.doc = new haste_document();
_this.doc.load(parts[0], function(ret) {
if (ret) {
_this.$code.html(ret.value);
_this.setTitle(ret.key);
_this.fullKey();
_this.$textarea.val('').hide();
_this.$box.show().focus();
_this.addLineNumbers(ret.lineCount);
}
else {
_this.newDocument();
}
}, this.lookupTypeByExtension(parts[1]));
};
// Duplicate the current document - only if locked
haste.prototype.duplicateDocument = function() {
if (this.doc.locked) {
var currentData = this.doc.data;
this.newDocument();
this.$textarea.val(currentData);
}
};
// Lock the current document
haste.prototype.lockDocument = function() {
var _this = this;
this.doc.save(this.$textarea.val(), function(err, ret) {
if (err) {
_this.showMessage(err.message, 'error');
}
else if (ret) {
_this.$code.html(ret.value);
_this.setTitle(ret.key);
var file = '/' + ret.key;
if (ret.language) {
file += '.' + _this.lookupExtensionByType(ret.language);
}
window.history.pushState(null, _this.appName + '-' + ret.key, file);
_this.fullKey();
_this.$textarea.val('').hide();
_this.$box.show().focus();
_this.addLineNumbers(ret.lineCount);
}
});
};
haste.prototype.configureButtons = function() {
var _this = this;
this.buttons = [
{
$where: $('#box2 .save'),
label: 'Save',
shortcutDescription: 'control + s',
shortcut: function(evt) {
return evt.ctrlKey && (evt.keyCode === 83);
},
action: function() {
if (_this.$textarea.val().replace(/^\s+|\s+$/g, '') !== '') {
_this.lockDocument();
}
}
},
{
$where: $('#box2 .new'),
label: 'New',
shortcut: function(evt) {
return evt.ctrlKey && evt.keyCode === 78;
},
shortcutDescription: 'control + n',
action: function() {
_this.newDocument(!_this.doc.key);
}
},
{
$where: $('#box2 .duplicate'),
label: 'Duplicate & Edit',
shortcut: function(evt) {
return _this.doc.locked && evt.ctrlKey && evt.keyCode === 68;
},
shortcutDescription: 'control + d',
action: function() {
_this.duplicateDocument();
}
},
{
$where: $('#box2 .raw'),
label: 'Just Text',
shortcut: function(evt) {
return evt.ctrlKey && evt.shiftKey && evt.keyCode === 82;
},
shortcutDescription: 'control + shift + r',
action: function() {
window.location.href = '/raw/' + _this.doc.key;
}
},
{
$where: $('#box2 .twitter'),
label: 'Twitter',
shortcut: function(evt) {
return _this.options.twitter && _this.doc.locked && evt.shiftKey && evt.ctrlKey && evt.keyCode == 84;
},
shortcutDescription: 'control + shift + t',
action: function() {
window.open('https://twitter.com/share?url=' + encodeURI(window.location.href));
}
}
];
for (var i = 0; i < this.buttons.length; i++) {
this.configureButton(this.buttons[i]);
}
};
haste.prototype.configureButton = function(options) {
// Handle the click action
options.$where.click(function(evt) {
evt.preventDefault();
if (!options.clickDisabled && $(this).hasClass('enabled')) {
options.action();
}
});
// Show the label
options.$where.mouseenter(function() {
$('#box3 .label').text(options.label);
$('#box3 .shortcut').text(options.shortcutDescription || '');
$('#box3').show();
$(this).append($('#pointer').remove().show());
});
// Hide the label
options.$where.mouseleave(function() {
$('#box3').hide();
$('#pointer').hide();
});
};
// Configure keyboard shortcuts for the textarea
haste.prototype.configureShortcuts = function() {
var _this = this;
$(document.body).keydown(function(evt) {
var button;
for (var i = 0 ; i < _this.buttons.length; i++) {
button = _this.buttons[i];
if (button.shortcut && button.shortcut(evt)) {
evt.preventDefault();
button.action();
return;
}
}
});
};
///// Tab behavior in the textarea - 2 spaces per tab
$(function() {
$('textarea').keydown(function(evt) {
if (evt.keyCode === 9) {
evt.preventDefault();
var myValue = ' ';
// http://stackoverflow.com/questions/946534/insert-text-into-textarea-with-jquery
// For browsers like Internet Explorer
if (document.selection) {
this.focus();
var sel = document.selection.createRange();
sel.text = myValue;
this.focus();
}
// Mozilla and Webkit
else if (this.selectionStart || this.selectionStart == '0') {
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos) + myValue +
this.value.substring(endPos,this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
}
else {
this.value += myValue;
this.focus();
}
}
});
});
+1
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

+3
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

+68
View File
@@ -0,0 +1,68 @@
<html>
<head>
<title>hastebin</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="solarized_dark.css"/>
<link rel="stylesheet" type="text/css" href="application.css"/>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="highlight.min.js"></script>
<script type="text/javascript" src="application.min.js"></script>
<meta name="robots" content="noindex,nofollow"/>
<script type="text/javascript">
var app = null;
// Handle pops
var handlePop = function(evt) {
var path = evt.target.location.pathname;
if (path === '/') { app.newDocument(true); }
else { app.loadDocument(path.substring(1, path.length)); }
};
// Set up the pop state to handle loads, skipping the first load
// to make chrome behave like others:
// http://code.google.com/p/chromium/issues/detail?id=63040
setTimeout(function() {
window.onpopstate = function(evt) {
try { handlePop(evt); } catch(err) { /* not loaded yet */ }
};
}, 1000);
// Construct app and load initial path
$(function() {
app = new haste('hastebin', { twitter: true });
handlePop({ target: window });
});
</script>
</head>
<body>
<ul id="messages"></ul>
<div id="key">
<div id="pointer" style="display:none;"></div>
<div id="box1">
<a href="/about.md" class="logo"></a>
</div>
<div id="box2">
<button class="save function button-picture">Save</button>
<button class="new function button-picture">New</button>
<button class="duplicate function button-picture">Duplicate & Edit</button>
<button class="raw function button-picture">Just Text</button>
<button class="twitter function button-picture">Twitter</button>
</div>
<div id="box3" style="display:none;">
<div class="label"></div>
<div class="shortcut"></div>
</div>
</div>
<div id="linenos"></div>
<pre id="box" style="display:none;" class="hljs" tabindex="0"><code></code></pre>
<textarea spellcheck="false" style="display:none;"></textarea>
</body>
</html>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

+4
View File
@@ -0,0 +1,4 @@
User-agent: *
Disallow: /*
Allow: /?okparam=
Allow: /$
+84
View File
@@ -0,0 +1,84 @@
/*
Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull <sourdrums@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #002b36;
color: #839496;
}
.hljs-comment,
.hljs-quote {
color: #586e75;
}
/* Solarized Green */
.hljs-keyword,
.hljs-selector-tag,
.hljs-addition {
color: #859900;
}
/* Solarized Cyan */
.hljs-number,
.hljs-string,
.hljs-meta .hljs-meta-string,
.hljs-literal,
.hljs-doctag,
.hljs-regexp {
color: #2aa198;
}
/* Solarized Blue */
.hljs-title,
.hljs-section,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #268bd2;
}
/* Solarized Yellow */
.hljs-attribute,
.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-class .hljs-title,
.hljs-type {
color: #b58900;
}
/* Solarized Orange */
.hljs-symbol,
.hljs-bullet,
.hljs-subst,
.hljs-meta,
.hljs-meta .hljs-keyword,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-link {
color: #cb4b16;
}
/* Solarized Red */
.hljs-built_in,
.hljs-deletion {
color: #dc322f;
}
.hljs-formula {
background: #073642;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
-69
View File
@@ -1,69 +0,0 @@
.highlight { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kn { font-weight: bold } /* Keyword.Namespace */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
.type-csharp .highlight .k { color: #0000FF }
.type-csharp .highlight .kt { color: #0000FF }
.type-csharp .highlight .nf { color: #000000; font-weight: normal }
.type-csharp .highlight .nc { color: #2B91AF }
.type-csharp .highlight .nn { color: #000000 }
.type-csharp .highlight .s { color: #A31515 }
.type-csharp .highlight .sc { color: #A31515 }
-255
View File
@@ -1,255 +0,0 @@
@import url(https://fonts.googleapis.com/css?family=Lato:300italic,700italic,300,700);
body {
padding:50px;
font:14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif;
color:#777;
font-weight:300;
}
h1, h2, h3, h4, h5, h6 {
color:#222;
margin:0 0 20px;
}
p, ul, ol, table, pre, dl {
margin:0 0 20px;
}
h1, h2, h3 {
line-height:1.1;
}
h1 {
font-size:28px;
}
h2 {
color:#393939;
}
h3, h4, h5, h6 {
color:#494949;
}
a {
color:#39c;
font-weight:400;
text-decoration:none;
}
a small {
font-size:11px;
color:#777;
margin-top:-0.6em;
display:block;
}
.wrapper {
width:860px;
margin:0 auto;
}
blockquote {
border-left:1px solid #e5e5e5;
margin:0;
padding:0 0 0 20px;
font-style:italic;
}
code, pre {
font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
color:#333;
font-size:12px;
}
pre {
padding:8px 15px;
background: #f8f8f8;
border-radius:5px;
border:1px solid #e5e5e5;
overflow-x: auto;
}
table {
width:100%;
border-collapse:collapse;
}
th, td {
text-align:left;
padding:5px 10px;
border-bottom:1px solid #e5e5e5;
}
dt {
color:#444;
font-weight:700;
}
th {
color:#444;
}
img {
max-width:100%;
}
header {
width:270px;
float:left;
position:fixed;
}
header ul {
list-style:none;
height:40px;
padding:0;
background: #eee;
background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd));
background: -webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
background: -o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
background: -ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
background: linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
border-radius:5px;
border:1px solid #d2d2d2;
box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0;
width:270px;
}
header li {
width:89px;
float:left;
border-right:1px solid #d2d2d2;
height:40px;
}
header ul a {
line-height:1;
font-size:11px;
color:#999;
display:block;
text-align:center;
padding-top:6px;
height:40px;
}
strong {
color:#222;
font-weight:700;
}
header ul li + li {
width:88px;
border-left:1px solid #fff;
}
header ul li + li + li {
border-right:none;
width:89px;
}
header ul a strong {
font-size:14px;
display:block;
color:#222;
}
section {
width:500px;
float:right;
padding-bottom:50px;
}
small {
font-size:11px;
}
hr {
border:0;
background:#e5e5e5;
height:1px;
margin:0 0 20px;
}
footer {
width:270px;
float:left;
position:fixed;
bottom:50px;
}
@media print, screen and (max-width: 960px) {
div.wrapper {
width:auto;
margin:0;
}
header, section, footer {
float:none;
position:static;
width:auto;
}
header {
padding-right:320px;
}
section {
border:1px solid #e5e5e5;
border-width:1px 0;
padding:20px 0;
margin:0 0 20px;
}
header a small {
display:inline;
}
header ul {
position:absolute;
right:50px;
top:52px;
}
}
@media print, screen and (max-width: 720px) {
body {
word-wrap:break-word;
}
header {
padding:0;
}
header ul, header p.view {
position:static;
}
pre, code {
word-wrap:normal;
}
}
@media print, screen and (max-width: 480px) {
body {
padding:15px;
}
header ul {
display:none;
}
}
@media print {
body {
padding:0.4in;
font-size:12pt;
color:#444;
}
}
+26
View File
@@ -0,0 +1,26 @@
/* global describe, it */
var assert = require('assert');
var DocumentHandler = require('../lib/document_handler');
var Generator = require('../lib/key_generators/random');
describe('document_handler', function() {
describe('randomKey', function() {
it('should choose a key of the proper length', function() {
var gen = new Generator();
var dh = new DocumentHandler({ keyLength: 6, keyGenerator: gen });
assert.equal(6, dh.acceptableKey().length);
});
it('should choose a default key length', function() {
var gen = new Generator();
var dh = new DocumentHandler({ keyGenerator: gen });
assert.equal(dh.keyLength, DocumentHandler.defaultKeyLength);
});
});
});
+33
View File
@@ -0,0 +1,33 @@
/* global describe, it */
const assert = require('assert');
const fs = require('fs');
const Generator = require('../../lib/key_generators/dictionary');
describe('RandomKeyGenerator', function() {
describe('randomKey', function() {
it('should throw an error if given no options', () => {
assert.throws(() => {
new Generator();
}, Error);
});
it('should throw an error if given no path', () => {
assert.throws(() => {
new Generator({});
}, Error);
});
it('should return a key of the proper number of words from the given dictionary', () => {
const path = '/tmp/haste-server-test-dictionary';
const words = ['cat'];
fs.writeFileSync(path, words.join('\n'));
const gen = new Generator({path}, () => {
assert.equal('catcatcat', gen.createKey(3));
});
});
});
});
+27
View File
@@ -0,0 +1,27 @@
/* global describe, it */
const assert = require('assert');
const Generator = require('../../lib/key_generators/phonetic');
const vowels = 'aeiou';
const consonants = 'bcdfghjklmnpqrstvwxyz';
describe('RandomKeyGenerator', () => {
describe('randomKey', () => {
it('should return a key of the proper length', () => {
const gen = new Generator();
assert.equal(6, gen.createKey(6).length);
});
it('should alternate consonants and vowels', () => {
const gen = new Generator();
const key = gen.createKey(3);
assert.ok(consonants.includes(key[0]));
assert.ok(consonants.includes(key[2]));
assert.ok(vowels.includes(key[1]));
});
});
});
+19
View File
@@ -0,0 +1,19 @@
/* global describe, it */
const assert = require('assert');
const Generator = require('../../lib/key_generators/random');
describe('RandomKeyGenerator', () => {
describe('randomKey', () => {
it('should return a key of the proper length', () => {
const gen = new Generator();
assert.equal(6, gen.createKey(6).length);
});
it('should use a key from the given keyset if given', () => {
const gen = new Generator({keyspace: 'A'});
assert.equal('AAAAAA', gen.createKey(6));
});
});
});
+54
View File
@@ -0,0 +1,54 @@
/* global it, describe, afterEach */
var assert = require('assert');
var winston = require('winston');
winston.remove(winston.transports.Console);
var RedisDocumentStore = require('../lib/document_stores/redis');
describe('redis_document_store', function() {
/* reconnect to redis on each test */
afterEach(function() {
if (RedisDocumentStore.client) {
RedisDocumentStore.client.quit();
RedisDocumentStore.client = false;
}
});
describe('set', function() {
it('should be able to set a key and have an expiration set', function(done) {
var store = new RedisDocumentStore({ expire: 10 });
store.set('hello1', 'world', function() {
RedisDocumentStore.client.ttl('hello1', function(err, res) {
assert.ok(res > 1);
done();
});
});
});
it('should not set an expiration when told not to', function(done) {
var store = new RedisDocumentStore({ expire: 10 });
store.set('hello2', 'world', function() {
RedisDocumentStore.client.ttl('hello2', function(err, res) {
assert.equal(-1, res);
done();
});
}, true);
});
it('should not set an expiration when expiration is off', function(done) {
var store = new RedisDocumentStore({ expire: false });
store.set('hello3', 'world', function() {
RedisDocumentStore.client.ttl('hello3', function(err, res) {
assert.equal(-1, res);
done();
});
});
});
});
});