yopass 2.2.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gemspec +4 -4
  3. data/Dockerfile +9 -14
  4. data/Gemfile +2 -1
  5. data/Gemfile.lock +3 -2
  6. data/README.md +41 -17
  7. data/lib/public/create-secret.html +32 -0
  8. data/lib/public/css/bootstrap.min.css +5 -0
  9. data/lib/public/display-secret.html +34 -0
  10. data/lib/public/fonts/glyphicons-halflings-regular.eot +0 -0
  11. data/lib/public/fonts/glyphicons-halflings-regular.svg +288 -0
  12. data/lib/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  13. data/lib/public/fonts/glyphicons-halflings-regular.woff +0 -0
  14. data/lib/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  15. data/lib/public/index.html +49 -0
  16. data/lib/public/js/angular-route.min.js +15 -0
  17. data/lib/public/js/angular.js +250 -0
  18. data/lib/public/js/app.js +65 -0
  19. data/lib/yopass.rb +75 -80
  20. data/spec/yopass_spec.rb +22 -15
  21. metadata +25 -52
  22. data/CHANGELOG.md +0 -39
  23. data/Procfile +0 -1
  24. data/conf/config.ru +0 -3
  25. data/conf/yopass.yaml +0 -10
  26. data/lib/static/flash/clippy.swf +0 -0
  27. data/lib/static/js/jquery.address.js +0 -598
  28. data/lib/static/js/jquery.js +0 -8829
  29. data/lib/static/packaged/css/font.css +0 -36
  30. data/lib/static/packaged/css/semantic.css +0 -17804
  31. data/lib/static/packaged/css/semantic.min.css +0 -14
  32. data/lib/static/packaged/fonts/basic.icons.eot +0 -0
  33. data/lib/static/packaged/fonts/basic.icons.svg +0 -450
  34. data/lib/static/packaged/fonts/basic.icons.ttf +0 -0
  35. data/lib/static/packaged/fonts/basic.icons.woff +0 -0
  36. data/lib/static/packaged/fonts/icons.eot +0 -0
  37. data/lib/static/packaged/fonts/icons.otf +0 -0
  38. data/lib/static/packaged/fonts/icons.svg +0 -399
  39. data/lib/static/packaged/fonts/icons.ttf +0 -0
  40. data/lib/static/packaged/fonts/icons.woff +0 -0
  41. data/lib/static/packaged/fonts/sans/OpenSans-Bold.ttf +0 -0
  42. data/lib/static/packaged/fonts/sans/OpenSans-Light.ttf +0 -0
  43. data/lib/static/packaged/fonts/sans/OpenSans.ttf +0 -0
  44. data/lib/static/packaged/fonts/sans/OpenSansLight-Italic.ttf +0 -0
  45. data/lib/static/packaged/fonts/sans/SourceSansPro-Bold.ttf +0 -0
  46. data/lib/static/packaged/fonts/sans/SourceSansPro-Regular.ttf +0 -0
  47. data/lib/static/packaged/images/loader-large-inverted.gif +0 -0
  48. data/lib/static/packaged/images/loader-large.gif +0 -0
  49. data/lib/static/packaged/images/loader-medium-inverted.gif +0 -0
  50. data/lib/static/packaged/images/loader-medium.gif +0 -0
  51. data/lib/static/packaged/images/loader-mini-inverted.gif +0 -0
  52. data/lib/static/packaged/images/loader-mini.gif +0 -0
  53. data/lib/static/packaged/images/loader-small-inverted.gif +0 -0
  54. data/lib/static/packaged/images/loader-small.gif +0 -0
  55. data/lib/static/packaged/javascript/semantic.js +0 -11944
  56. data/lib/static/packaged/javascript/semantic.min.js +0 -16
  57. data/lib/static/yopass.css +0 -23
  58. data/lib/static/yopass.js +0 -23
  59. data/lib/views/404.erb +0 -43
  60. data/lib/views/footer.erb +0 -9
  61. data/lib/views/get_secret.erb +0 -31
  62. data/lib/views/header.erb +0 -27
  63. data/lib/views/index.erb +0 -117
  64. data/lib/views/secret_url.erb +0 -87
  65. data/yopass.god +0 -11
data/lib/yopass.rb CHANGED
@@ -2,77 +2,86 @@ require 'memcached'
2
2
  require 'sinatra/base'
3
3
  require 'securerandom'
4
4
  require 'encryptor'
5
- require 'yaml'
6
5
  require 'uri'
7
6
  require 'yopass/sms_provider'
7
+ require 'sinatra/json'
8
+ require 'json'
9
+
10
+ def too_many_tries?(m, key)
11
+ key += key + '_ratelimit'
12
+ begin
13
+ result = m.get key
14
+ rescue Memcached::NotFound
15
+ m.set key, 1, 3600 * 24
16
+ return false
17
+ end
18
+ m.set key, result + 1
19
+
20
+ # This dude has tried to many times...
21
+ true if result >= 2
22
+ end
8
23
 
9
- # Share your secrets securely
10
24
  class Yopass < Sinatra::Base
25
+ helpers Sinatra::JSON
26
+
11
27
  configure :development do
12
28
  require 'sinatra/reloader'
13
29
  register Sinatra::Reloader
14
30
  end
15
31
 
16
32
  configure do
17
- config = ENV['YOPASS_CONFIG'] || 'conf/yopass.yaml'
18
- cfg = YAML.load_file(config)
19
- set :config, cfg
20
- set :base_url, ENV['YOPASS_BASE_URL'] || cfg['base_url']
21
- set :public_folder, File.dirname(__FILE__) + '/static'
22
- set :mc, Memcached.new(ENV['YOPASS_MEMCACHED_URL'] || cfg['memcached_url'])
23
- end
24
-
25
- get '/' do
26
- # display mobile number field if send_sms is true
27
- erb :index, locals: { send_sms: settings.config['send_sms'], error: nil }
28
- end
29
-
30
- get '/:key' do
31
- erb :get_secret, locals: { key: params[:key] }
33
+ set :public_folder, File.dirname(__FILE__) + '/public'
34
+ set :max_length, 10000
35
+ if ENV['YP_SECRET_MAX_LENGTH']
36
+ set :max_length, ENV['YP_SECRET_MAX_LENGTH'].to_i
37
+ end
32
38
  end
33
39
 
34
- get '/:key/:password' do
35
- # Disable all caching
36
- headers 'Cache-Control' => 'no-cache, no-store, must-revalidate'
37
- headers 'Pragma' => 'no-cache'
38
- headers 'Expires' => '0'
39
-
40
+ get '/v1/secret/:key/:password' do
41
+ m = Memcached.new(ENV['YP_MEMCACHED'] || 'localhost:11211')
40
42
  begin
41
- result = settings.mc.get params[:key]
43
+ result = m.get params[:key]
42
44
  rescue Memcached::NotFound
43
- return erb :'404'
45
+ status 404
46
+ return json message: 'Not found'
44
47
  end
45
- content_type 'text/plain'
46
48
 
47
49
  begin
48
50
  result = Encryptor.decrypt(value: result, key: params[:password])
49
51
  rescue OpenSSL::Cipher::CipherError
50
- settings.mc.delete(params[:key]) if too_many_tries?(params[:key])
51
- return 'Invalid decryption key'
52
+ m.delete(params[:key]) if too_many_tries?(m, params[:key])
53
+ status 401
54
+ return json message: 'Invalid decryption key'
52
55
  end
53
- settings.mc.delete params[:key]
54
- result
56
+ m.delete params[:key]
57
+ return json secret: result
55
58
  end
56
59
 
57
- post '/' do
58
- headers 'Cache-Control' => 'no-cache, no-store, must-revalidate'
59
- headers 'Pragma' => 'no-cache'
60
- headers 'Expires' => '0'
60
+ post '/v1/secret' do
61
+ begin
62
+ r = JSON.parse(request.body.read)
63
+ rescue JSON::ParserError
64
+ status 400
65
+ return json message: 'Bad request, seek API docs at https://github.com/jhaals/yopass'
66
+ end
61
67
 
62
- lifetime = params[:lifetime]
68
+ lifetime = r['lifetime']
63
69
  # calculate lifetime in secounds
64
70
  lifetime_options = { '1w' => 3600 * 24 * 7,
65
71
  '1d' => 3600 * 24,
66
72
  '1h' => 3600 }
67
73
 
68
74
  # Verify that user has posted a valid lifetime
69
- return 'Invalid lifetime' unless lifetime_options.include? lifetime
70
- return 'No secret submitted' if params[:secret].empty?
71
-
72
- if params[:secret].length >= settings.config['secret_max_length']
73
- return erb :index, locals: {
74
- send_sms: settings.config['send_sms'],
75
- error: 'This site is meant to store secrets not novels' }
75
+ status 400
76
+ # default lifetime
77
+ lifetime = '1d' if lifetime.nil?
78
+ secret = r['secret']
79
+ return json message: 'Invalid lifetime' unless lifetime_options.include? lifetime
80
+ return json message: 'No secret submitted' if secret.nil?
81
+ return json message: 'No secret submitted' if secret.empty?
82
+
83
+ if secret.length >= settings.max_length
84
+ return json message: 'error: This site is meant to store secrets not novels'
76
85
  end
77
86
 
78
87
  # goes in URL
@@ -80,54 +89,40 @@ class Yopass < Sinatra::Base
80
89
  # decryption_key goes in URL or via SMS if provider is configured
81
90
  decryption_key = SecureRandom.hex[0..8]
82
91
  # encrypt secret with generated decryption_key
83
- data = Encryptor.encrypt(params[:secret], key: decryption_key)
92
+ data = Encryptor.encrypt(secret, key: decryption_key)
84
93
 
94
+ m = Memcached.new(ENV['YP_MEMCACHED'] || 'localhost:11211')
85
95
  # store secret in memcached
86
96
  begin
87
- settings.mc.set key, data, lifetime_options[lifetime]
97
+ m.set key, data, lifetime_options[lifetime]
88
98
  rescue Memcached::ServerIsMarkedDead
89
- return erb :index, locals: {
90
- send_sms: settings.config['send_sms'],
91
- error: 'Error: Unable to contact memcached' }
99
+ status 500
100
+ return json message: 'Error: Unable to contact memcached'
92
101
  end
93
-
94
- if settings.config['send_sms'] == true && !params[:mobile_number].nil?
95
- # strip everything except digits
96
- mobile_number = params[:mobile_number].gsub(/[^0-9]/, '')
97
- # load specified sms provider
98
- sms = SmsProvider.create(settings.config['sms::provider'],
99
- settings.config['sms::settings'])
100
-
101
- unless params[:mobile_number].empty?
102
+ mobile_number = r['mobile_number']
103
+ if ENV['YP_SEND_SMS'] && !mobile_number.nil?
104
+ unless mobile_number.empty?
105
+ # strip everything except digits
106
+ mobile_number = mobile_number.gsub(/[^0-9]/, '')
107
+ # load SMS provider
108
+ sms_settings = JSON.parse(ENV['YP_SMS_SETTINGS'])
109
+ sms = SmsProvider.create(
110
+ sms_settings['provider'],
111
+ sms_settings['settings'])
102
112
  sms.send(mobile_number, decryption_key)
103
- return erb :secret_url, locals: {
104
- full_url: URI.join(settings.base_url, key + '/' + decryption_key),
105
- short_url: URI.join(settings.base_url, key),
106
- decryption_key: decryption_key,
107
- key_sent_to_mobile: true }
108
113
  end
109
114
  end
110
-
111
- erb :secret_url, locals: {
112
- full_url: URI.join(settings.base_url, key + '/' + decryption_key),
113
- short_url: URI.join(settings.base_url, key),
115
+ status 200
116
+ json key: key,
114
117
  decryption_key: decryption_key,
115
- key_sent_to_mobile: false }
118
+ full_url: "/v1/secret/#{key}/#{decryption_key}",
119
+ short_url: "/v1/secret/#{key}",
120
+ message: 'secret stored'
116
121
  end
117
- run! if app_file == $PROGRAM_NAME
118
- end
119
122
 
120
- def too_many_tries?(key)
121
- key += key + '_ratelimit'
122
- begin
123
- result = settings.mc.get key
124
- rescue Memcached::NotFound
125
- settings.mc.set key, 1, 3600 * 24
126
- return false
123
+ get '/' do
124
+ # Ugly way of serving index...
125
+ File.read(File.join(settings.public_folder, 'index.html'))
127
126
  end
128
- settings.mc.set key, result + 1
129
-
130
- # This dude has tried to many times...
131
- return true if result >= 2
132
- false
127
+ run! if app_file == $PROGRAM_NAME
133
128
  end
data/spec/yopass_spec.rb CHANGED
@@ -1,49 +1,56 @@
1
1
  require 'spec_helper'
2
-
2
+ require 'json'
3
3
  describe 'yopass' do
4
4
 
5
- it 'expect give the website' do
6
- get '/'
7
- expect(last_response.body).to match(/Share Secrets Securely/)
8
- end
9
-
10
5
  it 'expect complain about invalid lifetime' do
11
- post '/', 'lifetime' => 'foo'
6
+ post '/v1/secret', JSON.dump('lifetime' => 'foo')
12
7
  expect(last_response.body).to match(/Invalid lifetime/)
8
+ expect(last_response.status).to eq 400
13
9
  end
14
10
 
15
11
  it 'expect complain about missing secret' do
16
- post '/', 'lifetime' => '1h', 'secret' => ''
12
+ post '/v1/secret', JSON.dump('lifetime' => '1h', 'secret' => '')
17
13
  expect(last_response.body).to match(/No secret submitted/)
14
+ expect(last_response.status).to eq 400
15
+
18
16
  end
19
17
 
20
18
  it 'expect complain about secret being to long' do
21
- post '/', 'lifetime' => '1h', 'secret' => '0' * 1000000
19
+ post '/v1/secret', JSON.dump('lifetime' => '1h', 'secret' => '0' * 10000)
22
20
  expect(last_response.body).to match(/This site is meant to store secrets not novels/)
21
+ expect(last_response.status).to eq 400
23
22
  end
24
23
 
25
24
  it 'expect complain about not being able to connect to memcached' do
26
25
  allow_any_instance_of(Memcached).to receive(:set).and_raise(Memcached::ServerIsMarkedDead)
27
- post '/', 'lifetime' => '1h', 'secret' => '0' * 100
26
+ post '/v1/secret', JSON.dump('lifetime' => '1h', 'secret' => '0' * 100)
28
27
  expect(last_response.body).to match(/Unable to contact memcached/)
28
+ expect(last_response.status).to eq 500
29
29
  end
30
30
 
31
31
  it 'expect store secret' do
32
32
  allow_any_instance_of(Memcached).to receive(:set).and_return true
33
- post '/', 'lifetime' => '1h', 'secret' => '0' * 100
34
- expect(last_response.body).to match(/http:\/\/127.0.0.1:4567/)
33
+ post '/v1/secret', JSON.dump('lifetime' => '1h', 'secret' => 'test')
34
+
35
+ expect(last_response.body).to match(/full_url/)
36
+ expect(last_response.body).to match(/decryption_key/)
37
+ expect(last_response.body).to match(/key/)
38
+ expect(last_response.body).to match(/short_url/)
39
+ expect(last_response.status).to eq 200
35
40
  end
36
41
 
37
42
  it 'expect receive secret' do
38
43
  allow_any_instance_of(Memcached).to receive(:get).and_return("\xD5\x9E\xF7\xB1\xA0\xEC\xD6\xBD\xCA\x00nW\xAD\xB3\xF4\xDA")
39
44
  allow_any_instance_of(Memcached).to receive(:delete).and_return true
40
- get '/8937c6de9fb7b0ba9b7652b769743b4e/3af71378a'
45
+ get '/v1/secret/8937c6de9fb7b0ba9b7652b769743b4e/3af71378a'
41
46
  expect(last_response.body).to match(/hello world/)
47
+ expect(last_response.status).to eq 200
42
48
  end
43
49
 
44
50
  it 'expect raise Memcached::NotFound' do
45
51
  allow_any_instance_of(Memcached).to receive(:get).and_raise(Memcached::NotFound)
46
- get '/mykey/123'
47
- expect(last_response.body).to match(/Secret does not exist/)
52
+ get '/v1/secret/mykey/123'
53
+ expect(last_response.body).to match(/Not found/)
54
+ expect(last_response.status).to eq 404
48
55
  end
49
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yopass
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johan Haals
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-24 00:00:00.000000000 Z
11
+ date: 2015-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: encryptor
@@ -42,16 +42,22 @@ dependencies:
42
42
  name: rack
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.0
48
+ - - "<"
46
49
  - !ruby/object:Gem::Version
47
- version: '1.5'
50
+ version: '1.6'
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
52
- - - "~>"
55
+ - - ">="
53
56
  - !ruby/object:Gem::Version
54
- version: '1.5'
57
+ version: 1.5.0
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.6'
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: sinatra
57
63
  requirement: !ruby/object:Gem::Requirement
@@ -73,7 +79,7 @@ dependencies:
73
79
  - - "~>"
74
80
  - !ruby/object:Gem::Version
75
81
  version: '1.4'
76
- type: :development
82
+ type: :runtime
77
83
  prerelease: false
78
84
  version_requirements: !ruby/object:Gem::Requirement
79
85
  requirements:
@@ -117,56 +123,25 @@ files:
117
123
  - ".gemspec"
118
124
  - ".gitignore"
119
125
  - ".travis.yml"
120
- - CHANGELOG.md
121
126
  - Dockerfile
122
127
  - Gemfile
123
128
  - Gemfile.lock
124
129
  - LICENSE
125
- - Procfile
126
130
  - README.md
127
131
  - Rakefile
128
- - conf/config.ru
129
- - conf/yopass.yaml
130
132
  - config.ru
131
- - lib/static/flash/clippy.swf
132
- - lib/static/js/jquery.address.js
133
- - lib/static/js/jquery.js
134
- - lib/static/packaged/css/font.css
135
- - lib/static/packaged/css/semantic.css
136
- - lib/static/packaged/css/semantic.min.css
137
- - lib/static/packaged/fonts/basic.icons.eot
138
- - lib/static/packaged/fonts/basic.icons.svg
139
- - lib/static/packaged/fonts/basic.icons.ttf
140
- - lib/static/packaged/fonts/basic.icons.woff
141
- - lib/static/packaged/fonts/icons.eot
142
- - lib/static/packaged/fonts/icons.otf
143
- - lib/static/packaged/fonts/icons.svg
144
- - lib/static/packaged/fonts/icons.ttf
145
- - lib/static/packaged/fonts/icons.woff
146
- - lib/static/packaged/fonts/sans/OpenSans-Bold.ttf
147
- - lib/static/packaged/fonts/sans/OpenSans-Light.ttf
148
- - lib/static/packaged/fonts/sans/OpenSans.ttf
149
- - lib/static/packaged/fonts/sans/OpenSansLight-Italic.ttf
150
- - lib/static/packaged/fonts/sans/SourceSansPro-Bold.ttf
151
- - lib/static/packaged/fonts/sans/SourceSansPro-Regular.ttf
152
- - lib/static/packaged/images/loader-large-inverted.gif
153
- - lib/static/packaged/images/loader-large.gif
154
- - lib/static/packaged/images/loader-medium-inverted.gif
155
- - lib/static/packaged/images/loader-medium.gif
156
- - lib/static/packaged/images/loader-mini-inverted.gif
157
- - lib/static/packaged/images/loader-mini.gif
158
- - lib/static/packaged/images/loader-small-inverted.gif
159
- - lib/static/packaged/images/loader-small.gif
160
- - lib/static/packaged/javascript/semantic.js
161
- - lib/static/packaged/javascript/semantic.min.js
162
- - lib/static/yopass.css
163
- - lib/static/yopass.js
164
- - lib/views/404.erb
165
- - lib/views/footer.erb
166
- - lib/views/get_secret.erb
167
- - lib/views/header.erb
168
- - lib/views/index.erb
169
- - lib/views/secret_url.erb
133
+ - lib/public/create-secret.html
134
+ - lib/public/css/bootstrap.min.css
135
+ - lib/public/display-secret.html
136
+ - lib/public/fonts/glyphicons-halflings-regular.eot
137
+ - lib/public/fonts/glyphicons-halflings-regular.svg
138
+ - lib/public/fonts/glyphicons-halflings-regular.ttf
139
+ - lib/public/fonts/glyphicons-halflings-regular.woff
140
+ - lib/public/fonts/glyphicons-halflings-regular.woff2
141
+ - lib/public/index.html
142
+ - lib/public/js/angular-route.min.js
143
+ - lib/public/js/angular.js
144
+ - lib/public/js/app.js
170
145
  - lib/yopass.rb
171
146
  - lib/yopass/sms_provider.rb
172
147
  - lib/yopass/sms_provider/bulksms.rb
@@ -174,7 +149,6 @@ files:
174
149
  - spec/sms_provder_spec.rb
175
150
  - spec/spec_helper.rb
176
151
  - spec/yopass_spec.rb
177
- - yopass.god
178
152
  homepage: https://github.com/jhaals/yopass
179
153
  licenses:
180
154
  - Apache 2.0
@@ -183,7 +157,6 @@ post_install_message:
183
157
  rdoc_options: []
184
158
  require_paths:
185
159
  - lib
186
- - conf
187
160
  required_ruby_version: !ruby/object:Gem::Requirement
188
161
  requirements:
189
162
  - - ">="
data/CHANGELOG.md DELETED
@@ -1,39 +0,0 @@
1
- # Yopass changelog
2
-
3
- ### 2.2.0 - 2014-08-30
4
-
5
- - rate limiting - Secrets will be deleted after 3 failed attempts
6
- - fix issues building the docker container
7
-
8
- ### 2.1.1
9
-
10
- - fix missconfigured template rendering when sending decryption key over SMS
11
-
12
- ### 2.1.0
13
-
14
- - remove /get part from URLs
15
- - copy to clipboard for URLs
16
-
17
- ### 2.0.0
18
-
19
- - Rename `http_base_url` to base_url
20
- - Move configuration settings to environment variables
21
- - Use thin as webserver
22
- - Bump rspec version
23
- - Drop ruby 1.8.7 support
24
-
25
- ### 1.1.5
26
- - Ability to configure secret_max_length in yopass.yaml
27
-
28
- ### 1.1.4
29
- - remove gui messup
30
-
31
- ### 1.1.3
32
-
33
- - display placeholder for mobile number in form.
34
- - fixes bug where test would fail is memcached was running.
35
-
36
- ### 1.1.2
37
-
38
- - Typo
39
- - Shipp all fonts instead of loading them from external site. Caused insecure content warning
data/Procfile DELETED
@@ -1 +0,0 @@
1
- web: bundle exec rackup config.ru -p 4567 -s thin -o 0.0.0.0
data/conf/config.ru DELETED
@@ -1,3 +0,0 @@
1
- require 'rubygems'
2
- require 'yopass'
3
- run Yopass
data/conf/yopass.yaml DELETED
@@ -1,10 +0,0 @@
1
- memcached_url: 'localhost:11211'
2
- base_url: 'http://127.0.0.1:4567'
3
- secret_max_length: 100000
4
- send_sms: false
5
-
6
- sms::provider: 'bulksms'
7
- sms::settings:
8
- username: 'username'
9
- password: 'fancypass'
10
- sender: 'YoPass'
Binary file