desviar 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+ ruby '1.9.3'
3
+
4
+ gem 'sinatra'
5
+ gem 'dm-core'
6
+ gem 'dm-migrations'
7
+ gem 'dm-validations'
8
+ gem 'dm-timestamps'
9
+ gem 'syntaxi'
10
+ gem 'rack-recaptcha'
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ ### Desviar - High-security redirection ###
2
+
3
+ This is a Ruby-based app server built on Sinatra to create
4
+ preauthorized time-limited, random URIs used in devops deployment
5
+ scripts or in web applications such as confirmation emails.
6
+
7
+ It operates similarly to TinyURL or the Amazon S3 temporary-URI
8
+ feature: provide the tool with the URI to an existing secure resource,
9
+ specify a number of seconds you want to authorize references to it,
10
+ and you'll get back a temporary URI good for that amount of time.
11
+
12
+ You can set it up on a DMZ network or in the cloud behind an
13
+ iptables/nginx configuration to provide whatever ACL restrictions you
14
+ want, and you can reference any source URI (not just those stored on
15
+ S3).
16
+
17
+ Secure content is cached in memory (sqlite3) by default; for
18
+ troubleshooting, you can store content in a file.
19
+
20
+ #### Installation ####
21
+
22
+ Clone this repo, copy config/config.rb.example to config/config.rb, and
23
+ perform the following:
24
+
25
+ sudo apt-get install rack libsqlite3-dev
26
+ # package names above may differ if not using Ubuntu
27
+ sudo gem install bundler
28
+ sudo bundle install
29
+ rackup -p 4567
30
+
31
+ Default credential of [app](http://localhost:4567) is user _desviar_, pw _password_.
32
+
33
+ #### Usage ####
34
+
35
+ Commands:
36
+ * /create - generate a new pre-authenticated URI
37
+ * /desviar/xxx - retrieve pre-authenticated content (if a URISUFFIX was specified, it must be appended to xxx)
38
+ * /list - display a table of most-recently uploaded URIs
39
+ * /link/nnn - retrieve details
40
+
41
+ Here's an example of creating a new link via _curl_:
42
+
43
+ curl --digest --user desviar:password http://localhost:4567/create \
44
+ --data "desviar_redir_uri=http://localhost/test&desviar_expiration=1800&desviar_captcha=1&desviar_notes=testing"
45
+
46
+ #### Features implemented ####
47
+
48
+ - [x] HTTP digest authentication for user interface
49
+ - [ ] Parse htpasswd files to support multiple credentials
50
+ - [x] Bypass authentication for generated URIs
51
+ - [x] Basic HTTP authentication for remote URIs
52
+ - [ ] HTTP digest authentication for remote URIs
53
+ - [x] reCAPTCHA challenge for generated URIs
54
+ - [x] Listing of database contents
55
+ - [x] Choice of static or dynamic (REST) configuration
56
+ - [x] Encrypted database
57
+ - [ ] Memcached storage (for performance at scale)
58
+ - [x] Pre-shared/concealed URI suffix
59
+ - [ ] Activity log output (syslog)
60
+ - [x] Database cleanup tool
61
+ - [x] Tested under Ruby 1.9.3
62
+
63
+ #### License ####
64
+
65
+ Created under Apache license by rich braun, July 2013.
66
+
67
+ Copyright 2013 Richard Braun
68
+
69
+ Licensed under the Apache License, Version 2.0 (the "License");
70
+ you may not use this file except in compliance with the License.
71
+ You may obtain a copy of the License at
72
+ [Apache.org](http://www.apache.org/licenses/LICENSE-2.0)
@@ -0,0 +1,89 @@
1
+ # Configuration values for Desviar
2
+ #
3
+ # Created 14 Jul 2013 by rich braun
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ $config = {
12
+
13
+ :msg_title => "Page title for all generated HTML output",
14
+ :title => "Desviar",
15
+
16
+ :msg_uriprefix => "Prefix is an arbitrary string placed at beginning of URI",
17
+ :uriprefix => "012",
18
+
19
+ :msg_urisuffix => "Suffix is a pre-shared hidden string that must be appended to fetch URI; leave blank unless you need extra security",
20
+ :urisuffix => "",
21
+
22
+ :msg_hashlength => "Length of generated URL; if you like TinyURL, try a value of 3 or 4",
23
+ :hashlength => 32,
24
+
25
+ :msg_exp => "Default expiration interval, in seconds",
26
+ :exp => 900,
27
+
28
+ :msg_authprompt => "AuthPrompt appears in the browser authentication dialog",
29
+ :authprompt => "Please Authenticate",
30
+
31
+ :msg_adminuser => "Administrative username - has access to all records",
32
+ :adminuser => "desviar",
33
+
34
+ :msg_adminpw => "Admin PW secures the UI",
35
+ :adminpw => "password",
36
+
37
+ :msg_authsalt => "AuthSalt is used to randomize http-digest hash",
38
+ :authsalt => "notveryrandom",
39
+
40
+ :msg_dbmethod => "DB method - sqlite path name; use sqlite:///path/file.db to store on disk",
41
+ :dbmethod => "sqlite:///dev/shm/desviar",
42
+
43
+ ### TODO: figure out how to maintain a persistent thread for memory DB
44
+ # dbmethod => "sqlite::memory:",
45
+
46
+ :msg_dbencrypt => "Method for encrypting local database, see optvals for list of values",
47
+ :dbencrypt => "aes-256-cbc",
48
+
49
+ :msg_cryptkey => "32-byte encryption key, or nil to generate random one at startup",
50
+ :cryptkey => nil,
51
+
52
+ :msg_captchapub => "Public key for reCAPTCHA - see http://www.google.com/recaptcha/whyrecaptcha",
53
+ :captchapub => "",
54
+ :msg_captchapriv => "Private key for reCAPTCHA",
55
+ :captchapriv => "",
56
+
57
+ :msg_recordsmax => "Records to display on /list",
58
+ :recordsmax => 150,
59
+
60
+ :msg_contentmax => "Max content size to cache",
61
+ :contentmax => 4194304,
62
+
63
+ :msg_log_facility => "Syslog facility - false to disable",
64
+ :log_facility => Syslog::LOG_LOCAL1,
65
+
66
+ # Hidden config items concealed from UI/API
67
+ :hidden => [ "hidden", "hashed" ],
68
+
69
+ # Hashed config items - secure passwords
70
+ :hashed => [ "authsalt", "adminpw", "cryptkey", "captchapriv" ],
71
+
72
+ :msg_debug => "Debug mode",
73
+ :debug => false
74
+ }
75
+
76
+ # Option values for drop-down selections
77
+
78
+ $optvals = {
79
+ :dbencrypt => [ false, "aes-256-cbc" ],
80
+ :debug => [ true, false ],
81
+ :log_facility => [
82
+ Syslog::LOG_LOCAL0,
83
+ Syslog::LOG_LOCAL1,
84
+ Syslog::LOG_LOCAL2,
85
+ Syslog::LOG_LOCAL3
86
+ ],
87
+ :hashlength => [ 3, 4, 6, 8, 12, 24, 32, 48, 64 ],
88
+ :recordsmax => [ 50, 100, 150, 250, 500 ]
89
+ }
data/config.ru ADDED
@@ -0,0 +1,13 @@
1
+ require File.expand_path '../desviar.rb', __FILE__
2
+ log = File.new("desviar.log", "a+")
3
+ $stdout.reopen(log)
4
+ $stderr.reopen(log)
5
+
6
+ run Rack::URLMap.new({
7
+ "/" => Desviar::Authorized,
8
+ "/0/config" => Desviar::Authorized,
9
+ "/0/create" => Desviar::Authorized,
10
+ "/0/link" => Desviar::Authorized,
11
+ "/0/list" => Desviar::Authorized,
12
+ "/desviar" => Desviar::Public
13
+ })
data/desviar.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ require './desviar'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.platform = Gem::Platform::RUBY
5
+ spec.name = "desviar"
6
+ spec.summary = "Preauthorized secure/random URI redirection"
7
+ spec.authors = ["Rich Braun"]
8
+ spec.email = "richb@instantlinux.net"
9
+ spec.homepage = "http://github.com/instantlinux/desviar"
10
+ spec.rubyforge_project = spec.name
11
+ spec.version = Desviar::VERSION
12
+ spec.date = Desviar::RELEASE
13
+ # spec.test_files = spec.files.select{ |path| path =~ /^test\/.*/ }
14
+ spec.require_paths = ["config", "lib", "public", "views"]
15
+ spec.files = %x[git ls-files].split.reject do |out|
16
+ out =~ %r{^\.} || out =~ %r{/^doc/api/}
17
+ end
18
+ spec.description = <<-end.gsub /^ /,''
19
+ Desviar provides URL redirection; some possible applications include:
20
+ - Web signup process
21
+ - Continuous-deploy servers
22
+ - Online ticket sales
23
+ end
24
+ spec.post_install_message = <<-end.gsub(/^[ ]{4}/,'')
25
+ #{'-'*78}
26
+ Desviar v#{spec.version}
27
+
28
+ Thanks for using Desviar.
29
+ #{'-'*78}
30
+ end
31
+ spec.add_dependency "sinatra", ">= 1.4"
32
+ end
data/desviar.rb ADDED
@@ -0,0 +1,239 @@
1
+ # Desviar - URL redirection for security applications
2
+ #
3
+ # Created 14 Jul 2013
4
+ #
5
+ # Copyright 2013 Richard Braun
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ require 'sinatra/base'
14
+ require 'securerandom'
15
+ require 'dm-core'
16
+ require 'dm-migrations'
17
+ require 'dm-validations'
18
+ require 'dm-timestamps'
19
+ require 'syntaxi'
20
+ require 'syslog'
21
+ require 'net/http'
22
+ #require 'test/unit'
23
+ require 'rack/test'
24
+ require 'rack/recaptcha'
25
+
26
+ require './config/config'
27
+ require './lib/version'
28
+ require './lib/encrypt'
29
+ require './lib/model'
30
+ # Auth parsing is work-in-progress
31
+ # require './lib/auth.rb'
32
+
33
+ module Desviar
34
+ class Authorized < Sinatra::Base
35
+
36
+ configure do
37
+ DataMapper::Logger.new($stdout, :debug) if $config[:debug]
38
+ DataMapper.setup(:default, $config[:dbmethod])
39
+ DataMapper.auto_upgrade! if DataMapper.respond_to?(:auto_upgrade!)
40
+ $config[:cryptkey] = SecureRandom.base64(32) if $config[:cryptkey].nil?
41
+ end
42
+
43
+ get '/' do
44
+ redirect '/create'
45
+ end
46
+
47
+ # create
48
+ get '/create' do
49
+ puts request.env.inspect if $config[:debug]
50
+ erb :create
51
+ end
52
+
53
+ # submit
54
+ post '/create' do
55
+ # Create a new data record, generating the random URI and omitting
56
+ # remote-access credentials if specified.
57
+ @desviar = Desviar::Model::Main.new(params.merge({
58
+ :temp_uri => "#{$config[:uriprefix]}#{SecureRandom.urlsafe_base64($config[:hashlength])[0,$config[:hashlength]]}#{$config[:urisuffix]}",
59
+ :expires_at => Time.now + params[:expiration].to_i,
60
+ :captcha_validated => false
61
+ }).delete_if {|key, val| key == "remoteuser" || key == "remotepw"})
62
+
63
+ # Cache the remote URI
64
+ object = URI.parse(@desviar[:redir_uri])
65
+ http = Net::HTTP.new(object.host, object.port)
66
+ http.use_ssl = @desviar[:redir_uri].index('https') == 0
67
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
68
+ req = Net::HTTP::Get.new(object.request_uri)
69
+ if params[:remoteuser] != ''
70
+ req.basic_auth params[:remoteuser], params[:remotepw]
71
+ end
72
+ response = http.request(req)
73
+ if !$config[:dbencrypt]
74
+ @desviar[:content] = response.body[0, $config[:contentmax]]
75
+ else
76
+ obj = Desviar::EncryptedItem::Encryptor.new(
77
+ response.body[0, $config[:contentmax]], $config[:cryptkey])
78
+ @desviar[:content] = obj.encrypted_data
79
+ @desviar[:hmac] = obj.hmac
80
+ @desviar[:cipher_iv] = obj.iv
81
+ end
82
+
83
+ # Insert the new record and display the new link
84
+ if @desviar.save
85
+ Desviar::Public::log "Created #{@desviar.id} #{@desviar.redir_uri} #{@desviar.expires_at} #{request.ip}"
86
+ redirect "/link/#{@desviar.id}"
87
+ else
88
+ error 400
89
+ end
90
+ end
91
+
92
+ # show link ID
93
+ get '/link/:id' do
94
+ @desviar = Desviar::Model::Main.get(params[:id])
95
+ if @desviar && DateTime.now < @desviar[:expires_at]
96
+ erb :show
97
+ else
98
+ error 404
99
+ end
100
+ end
101
+
102
+ # clean out expired records
103
+ get '/clean' do
104
+ # TODO: figure out the clean "native" way of DataMapper::Collection.destroy
105
+ # - but this works fine for small databases
106
+ @desviar = DataMapper.repository(:default).adapter
107
+ @records = Desviar::Model::Main.all(:expires_at.lt => DateTime.now)
108
+ count = 0
109
+ @records.each do |item|
110
+ @desviar.execute("DELETE FROM desviar_data WHERE id=#{item.id};")
111
+ count += 1
112
+ end
113
+ Desviar::Public::log "Cleaned #{count} records" if count != 0
114
+ redirect "/list"
115
+ end
116
+
117
+ # list of most recent records
118
+ get '/list' do
119
+ @desviar = Desviar::Model::Main.all(:limit => $config[:recordsmax], :order => [ :created_at.desc ])
120
+ @total = @desviar.length
121
+ @count = [ @total, $config[:recordsmax] ].min
122
+ erb :list
123
+ end
124
+
125
+ # configuration
126
+ get '/config' do
127
+ erb :config
128
+ end
129
+
130
+ # submit
131
+ post '/config' do
132
+ params['config'].each do |opt, val|
133
+ if $config[opt.to_sym].class == Fixnum
134
+ $config[opt.to_sym] = val.to_i
135
+ elsif val != "" || !$config[:hashed].include?(opt)
136
+ $config[opt.to_sym] = case val
137
+ when "true" then true
138
+ when "false" then false
139
+ when "nil" then nil
140
+ else val
141
+ end
142
+ end
143
+ end
144
+
145
+ DataMapper::Logger.new($stdout, :debug) if $config[:debug]
146
+ $config[:cryptkey] = SecureRandom.base64(32) if $config[:cryptkey].nil?
147
+
148
+ puts $config.inspect if $config[:debug]
149
+ Desviar::Public::log "Configuration updated"
150
+ redirect "/list"
151
+ end
152
+
153
+ def self.new(*)
154
+ # TODO: htpasswd parsing
155
+ # Desviar::Auth::authenticate!
156
+ app = Rack::Auth::Digest::MD5.new(super) do |username|
157
+ {$config[:adminuser] => $config[:adminpw]}[username]
158
+ end
159
+ app.realm = $config[:authprompt]
160
+ app.opaque = $config[:authsalt]
161
+ app
162
+ end
163
+
164
+ end
165
+
166
+ #############################################
167
+ # Class Desviar::Public - routes without auth
168
+
169
+ class Public < Sinatra::Base
170
+
171
+ configure do
172
+ use Rack::Recaptcha, :public_key => $config[:captchapub], :private_key => $config[:captchapriv]
173
+ helpers Rack::Recaptcha::Helpers
174
+ end
175
+
176
+ # display content
177
+ get '/:temp_uri' do
178
+ @desviar = Desviar::Model::Main.first(:temp_uri => params[:temp_uri])
179
+ cache_control :public, :max_age => 30
180
+ if @desviar && DateTime.now < @desviar[:expires_at]
181
+ if @desviar[:captcha] && !@desviar[:captcha_validated]
182
+ @button = @desviar[:captcha_button]
183
+ erb :captcha
184
+ else
185
+ @desviar.update(:captcha_validated => false) if @desviar[:captcha_validated]
186
+ if !$config[:dbencrypt]
187
+ @content = @desviar[:content]
188
+ else
189
+ obj = Desviar::EncryptedItem::Decryptor::for({
190
+ 'cipher' => $config[:dbencrypt],
191
+ 'version' => 2,
192
+ 'encrypted_data' => @desviar[:content],
193
+ 'iv' => Base64.encode64(@desviar[:cipher_iv]),
194
+ 'hmac' => @desviar[:hmac]}, $config[:cryptkey])
195
+ @content = obj.for_decrypted_item
196
+ end
197
+ Desviar::Public::log "Fetched #{@desviar.id} #{@desviar.redir_uri} #{@desviar.content.bytesize} #{@desviar.notes[0,50]}"
198
+ erb :content, :layout => false
199
+ end
200
+ else
201
+ error 404
202
+ end
203
+ end
204
+
205
+ # handle reCAPTCHA
206
+ post '/:temp_uri' do
207
+ if recaptcha_valid?
208
+ @desviar = Desviar::Model::Main.first(:temp_uri => params[:temp_uri],
209
+ :fields => [ :id, :temp_uri, :captcha_validated ])
210
+ @desviar.update(:captcha_validated => true)
211
+ end
212
+ redirect "/desviar/#{params[:temp_uri]}"
213
+ end
214
+
215
+ def self.log(message, priority = Syslog::LOG_INFO)
216
+ if $config[:log_facility]
217
+ Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS | $config[:log_facility]) { |obj| obj.info message }
218
+ end
219
+ puts "#{Time.now} #{message}" if $config[:debug]
220
+ end
221
+ end
222
+
223
+ =begin
224
+ # TODO - switch to MiniTest, move to test subdir
225
+ class Test <Test::Unit::TestCase
226
+ include Rack::Test::Methods
227
+
228
+ def app
229
+ Desviar
230
+ end
231
+
232
+ def test_list
233
+ get '/list'
234
+ assert last_response.ok?
235
+ end
236
+ end
237
+ =end
238
+ end
239
+