tentd 0.0.1

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 (101) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +9 -0
  5. data/Guardfile +6 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +49 -0
  8. data/Rakefile +8 -0
  9. data/bin/tent-server +3 -0
  10. data/lib/tentd.rb +31 -0
  11. data/lib/tentd/api.rb +58 -0
  12. data/lib/tentd/api/apps.rb +196 -0
  13. data/lib/tentd/api/authentication_finalize.rb +12 -0
  14. data/lib/tentd/api/authentication_lookup.rb +27 -0
  15. data/lib/tentd/api/authentication_verification.rb +50 -0
  16. data/lib/tentd/api/authorizable.rb +21 -0
  17. data/lib/tentd/api/authorization.rb +14 -0
  18. data/lib/tentd/api/core_profile_data.rb +45 -0
  19. data/lib/tentd/api/followers.rb +218 -0
  20. data/lib/tentd/api/followings.rb +241 -0
  21. data/lib/tentd/api/groups.rb +161 -0
  22. data/lib/tentd/api/middleware.rb +32 -0
  23. data/lib/tentd/api/posts.rb +373 -0
  24. data/lib/tentd/api/profile.rb +78 -0
  25. data/lib/tentd/api/router.rb +123 -0
  26. data/lib/tentd/api/router/caching_headers.rb +49 -0
  27. data/lib/tentd/api/router/extract_params.rb +88 -0
  28. data/lib/tentd/api/router/serialize_response.rb +38 -0
  29. data/lib/tentd/api/user_lookup.rb +10 -0
  30. data/lib/tentd/core_ext/hash/slice.rb +29 -0
  31. data/lib/tentd/datamapper/array_property.rb +23 -0
  32. data/lib/tentd/datamapper/query.rb +19 -0
  33. data/lib/tentd/json_patch.rb +181 -0
  34. data/lib/tentd/model.rb +30 -0
  35. data/lib/tentd/model/app.rb +68 -0
  36. data/lib/tentd/model/app_authorization.rb +113 -0
  37. data/lib/tentd/model/follower.rb +105 -0
  38. data/lib/tentd/model/following.rb +100 -0
  39. data/lib/tentd/model/group.rb +24 -0
  40. data/lib/tentd/model/mention.rb +19 -0
  41. data/lib/tentd/model/notification_subscription.rb +56 -0
  42. data/lib/tentd/model/permissible.rb +227 -0
  43. data/lib/tentd/model/permission.rb +28 -0
  44. data/lib/tentd/model/post.rb +178 -0
  45. data/lib/tentd/model/post_attachment.rb +27 -0
  46. data/lib/tentd/model/post_version.rb +64 -0
  47. data/lib/tentd/model/profile_info.rb +80 -0
  48. data/lib/tentd/model/random_public_id.rb +46 -0
  49. data/lib/tentd/model/serializable.rb +58 -0
  50. data/lib/tentd/model/type_properties.rb +36 -0
  51. data/lib/tentd/model/user.rb +39 -0
  52. data/lib/tentd/model/user_scoped.rb +14 -0
  53. data/lib/tentd/notifications.rb +13 -0
  54. data/lib/tentd/notifications/girl_friday.rb +30 -0
  55. data/lib/tentd/notifications/sidekiq.rb +50 -0
  56. data/lib/tentd/tent_type.rb +20 -0
  57. data/lib/tentd/tent_version.rb +41 -0
  58. data/lib/tentd/version.rb +3 -0
  59. data/spec/fabricators/app_authorizations_fabricator.rb +5 -0
  60. data/spec/fabricators/apps_fabricator.rb +11 -0
  61. data/spec/fabricators/followers_fabricator.rb +14 -0
  62. data/spec/fabricators/followings_fabricator.rb +17 -0
  63. data/spec/fabricators/groups_fabricator.rb +3 -0
  64. data/spec/fabricators/mentions_fabricator.rb +3 -0
  65. data/spec/fabricators/notification_subscriptions_fabricator.rb +4 -0
  66. data/spec/fabricators/permissions_fabricator.rb +1 -0
  67. data/spec/fabricators/post_attachments_fabricator.rb +8 -0
  68. data/spec/fabricators/post_versions_fabricator.rb +12 -0
  69. data/spec/fabricators/posts_fabricator.rb +12 -0
  70. data/spec/fabricators/profile_infos_fabricator.rb +30 -0
  71. data/spec/integration/api/apps_spec.rb +466 -0
  72. data/spec/integration/api/followers_spec.rb +535 -0
  73. data/spec/integration/api/followings_spec.rb +688 -0
  74. data/spec/integration/api/groups_spec.rb +207 -0
  75. data/spec/integration/api/posts_spec.rb +874 -0
  76. data/spec/integration/api/profile_spec.rb +285 -0
  77. data/spec/integration/api/router_spec.rb +102 -0
  78. data/spec/integration/model/app_authorization_spec.rb +59 -0
  79. data/spec/integration/model/app_spec.rb +63 -0
  80. data/spec/integration/model/follower_spec.rb +344 -0
  81. data/spec/integration/model/following_spec.rb +97 -0
  82. data/spec/integration/model/group_spec.rb +39 -0
  83. data/spec/integration/model/notification_subscription_spec.rb +145 -0
  84. data/spec/integration/model/post_spec.rb +658 -0
  85. data/spec/spec_helper.rb +37 -0
  86. data/spec/support/expect_server.rb +3 -0
  87. data/spec/support/json_request.rb +54 -0
  88. data/spec/support/with_constant.rb +23 -0
  89. data/spec/support/with_warnings.rb +6 -0
  90. data/spec/unit/api/authentication_finalize_spec.rb +45 -0
  91. data/spec/unit/api/authentication_lookup_spec.rb +65 -0
  92. data/spec/unit/api/authentication_verification_spec.rb +50 -0
  93. data/spec/unit/api/authorizable_spec.rb +50 -0
  94. data/spec/unit/api/authorization_spec.rb +44 -0
  95. data/spec/unit/api/caching_headers_spec.rb +121 -0
  96. data/spec/unit/core_profile_data_spec.rb +64 -0
  97. data/spec/unit/json_patch_spec.rb +407 -0
  98. data/spec/unit/tent_type_spec.rb +28 -0
  99. data/spec/unit/tent_version_spec.rb +68 -0
  100. data/tentd.gemspec +36 -0
  101. metadata +435 -0
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rbx/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --backtrace
@@ -0,0 +1,8 @@
1
+ source_key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBM2Nvc0tLYnJWQllHTlI5WEE5WTc1L2FJbndPUWZ6L1dzK29GblQrR1hhVzV0Y3poCnpybTlyckU4WkpTWmtOaEpQQkZaMEpLMjI2M3FWSHkxWW45MC9XdUZ0aEZxbGdVNUgxbS9TTHJuelgrUzd2NHcKZk9zWU1xV1VvNVNzVXpLV3B0REhXNjMvQjlCNjBtck9OZnkwRU0yZjM0b05GMTlLTFM5ZTZKQ2t0aWViQXg2VAppaXE2OEtkVW5rODNVZjhYRkVOWi9iK2p3N2FaekdQNVY0R0JvMmhud1hEbFUxanlwNkVnVFUzdThNWFpHRUU2CjV4MWJlYmtIYUdPZXlGRUNTQUJsTEZBUGwrMDZsNEluaE0rMC9RSmJUTnlWdUNHaUtDNStlU3FwREdtdlJxK3MKTC9sNG9zMTBOUEdLU0c1eDRXcFIycUVRQXVxYTZPV0dTMlE0SHdJREFRQUJBb0lCQVFDeXlrckV6cUtBVzJ6UApvQjhHUWNwekdRTlRwSXowZDZMOTBCYU1oK3dxUy9Ha1E3QjRkTFViUVZjZEFjbTF3UlZ3YmRCSVdpMDhkRHVsCnRnNkdnNWJzdjZPL2ZOUytjU0YyUzJQdkhuVEU3U1dtc1pTbTd1SEgya0V6aVNOTndrYzkzS29KRnYreTdmWkUKNzhLaU5MOTNtRHRiK2E3Sis1QVJVdEdnaXhHc29Fb3FYeU9xYVJNNFBmK1pwSHZYcVZLR2xUM0tNaDBCQVM4TQpuK1ZtblpzRDUyMFNETXR0SUJQYXg3U2pPb2NQQ3lmOEt5dHVxblRRSC9RMjVsSE5HcmI1VmQxYzd4dFJ1SlRDCnVGWmFhczAwSzZBUG5uZDZkak1rM3kxSTJSNG8vRUlBOFZhRWNoc0ZCUXd5ZGlxQThkL0gyZTd5czRBd1RHL0sKbVFBMzk0eDVBb0dCQVBwUnNRdStib1dvclFRWC9teTdyU0M4QzFRQmlYQVBNUGxhU3A1d29WMlEzbnQzL1l4TApYbVh6SFdBTlU2dWo2Q01vTHg3UWtXMGppOXFySk9aR2JUejZ0VTFBOHFHL28yRVVKSldJN3F0Qnh5R291YS8yCjcraDliOGJYZDBNZDVWYXp5S21hSEE5aHA3Qm04Y2hpaTlNUUhBTFVrNUIwbyt5azhoUHVFOXl6QW9HQkFPTFMKdXY5ZE8wdm9wTVA2aHpYYitIamJodkZJVXBudTNOR2srQVdWQ3Rlc2NHRzZkMUdqR1loaUxmN2p5eGdUQ3NBegpBek9kVEs3eXI5bXZpTHJKb2J2a05pbG5SNzBnRHNkckJuK2p0ajQvb1MwaUpRWTB6WlpSVTZ2bzhIM3cvSGxyCjVMRVFPOUVGOCs1bWRlT3lIMDI4b1lUY1IvaWNTcC9vV3RiTG53VGxBb0dBWWh5WXp5aVJ1ek9VdE5FT3VPR0sKaHhVTlA1em1tSlJydHFCTU5QT2lXOEVIWXM5eUFvWWI5c3VtVE5xTVcrNy9jcUF5YjlxQjFZd2tLYzRBeFh6LwpIZktLRTBDTW1SYzYyemNBNjlkaTdKNzRoTm5VQmdNOG54eGpMa1dQaWkveWp0d2luMDgzQmxSWlhJdk00cVMxCmQwR09LUkhXMEx6VzcwN3JUeUoyaUg4Q2dZRUF3cGdwNStWemRzZExlL3NXUHdYTjRObnRwbGoyekt0WmRONkUKRGozMHhGMWpPT1RCY3g5clMwOTN5SUpqZmU3d1BUNUdrK1J5b25FQW50QnlqRlZwMVFtUDBldVNaMVgyZCsyQQo4TVppRm50K2Fuc3RxbXBvcW5weFB6NGovTmhmc2tmM05sVUlER2FBQk5xUWIxMGtjQXZSd21zOXI3TmVibHZvCmV2ak1IMlVDZ1lFQWpnYlRGcnV0Ri9Kam82bW4zYW1HNVBWVGJ1S2NRUEdwUEZWRm1tZFlreCthRXk4b2xEV1EKcFF2Y0k0U0F4UVRnaGFXOUZkc3ZBUEtVMkdUbTZFR2VlR0ZuMERTZExPZ2ZLSW52UFMrbUo3NEhBTnllQWpmbApxR1diTWJRcXFtclQ4akVFemNRWENZYnVNZndZOTJyTVZwVXhRc3VVb1dzWXN2aVFkOGM5ZlN3PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
2
+ before_script:
3
+ - psql -c 'create database tentd_test;' -U postgres
4
+ env:
5
+ - TEST_DATABASE_URL=postgres://postgres@localhost/tentd_test
6
+ rvm:
7
+ - 1.9.3
8
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rack-test', :git => 'https://github.com/brynary/rack-test.git'
6
+ gem 'tent-client', :git => 'git://github.com/tent/tent-client-ruby.git', :branch => 'master'
7
+ gem 'rb-fsevent', '~> 0.9.1'
8
+ gem 'do_jdbc', :platform => :jruby
9
+ gem 'girl_friday', '~> 0.10'
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/tentd/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
4
+ watch(%r{^lib/[^/]+\.rb$}) { "spec" }
5
+ watch(%r{spec/(spec_helper|support/).*\.rb}) { "spec" }
6
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Apollic Software, LLC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # tentd ![Build Status](https://magnum.travis-ci.com/tent/tentd.png?branch=master&token=YmxLSPgdpsxNUMWJpzRx)
2
+
3
+ tentd is an **alpha** implementation of a [Tent Protocol](http://tent.io) server.
4
+ It currently contains **broken code, ugly code, many bugs, and security flaws**.
5
+ The code should only be used to experiment with how Tent works. Under no
6
+ circumstances should the code in its current form be used for data that is
7
+ supposed to be private. All of the implemented APIs are in flux, and are
8
+ expected to change heavily before the Tent 1.0 release.
9
+
10
+
11
+ ## Requirements
12
+
13
+ TentD is written using Ruby 1.9 with Rack and Datamapper and is only tested with
14
+ PostgreSQL. The code needs a few fixes to work with 1.8 and other databases.
15
+
16
+ If you have Ruby 1.9, Bundler, and PostgreSQL installed, this should get the
17
+ tests running:
18
+
19
+ ```shell
20
+ createdb tent_server_test
21
+ bundle install
22
+ rake
23
+ ```
24
+
25
+ If you want to run this as a Tent server, you should use
26
+ [tentd-admin](https://github.com/tent/tentd-admin).
27
+
28
+
29
+ ## Contributions
30
+
31
+ If you want to help out with the TentD code instead of writing Tent clients and
32
+ applications, here are some areas that can be worked on:
33
+
34
+ - Fix database queries. There are a bunch of suboptimal uses of the database,
35
+ and basically no indexes. Low hanging fruit would be to turn on logging while
36
+ running the tests and index all the queries.
37
+ - Add data validation/normalization.
38
+ - Audit security.
39
+ - Refactor. The current code was hacked together quickly and is pretty ugly.
40
+ - Add tests. There are quite a few areas that aren't tested completely.
41
+ - Fix tests. A lot of tests are written as integration tests and depend on the
42
+ database, many would be much faster as unit tests that don't hit the database.
43
+
44
+ Please note that we are not looking for Pull Requests that make fundamental
45
+ changes to how the Tent Protocol works.
46
+
47
+ ### Contributors
48
+
49
+ - [Jonas Schneider](https://github.com/jonasschneider)
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = 'spec/**/*_spec.rb'
7
+ end
8
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tent-server'
@@ -0,0 +1,31 @@
1
+ require 'tentd/version'
2
+ require 'tent-client'
3
+
4
+ module TentD
5
+ autoload :API, 'tentd/api'
6
+ autoload :Action, 'tentd/action'
7
+ autoload :JsonPatch, 'tentd/json_patch'
8
+ autoload :TentVersion, 'tentd/tent_version'
9
+ autoload :TentType, 'tentd/tent_type'
10
+
11
+ def self.new(options={})
12
+ if options[:database] || ENV['DATABASE_URL']
13
+ DataMapper.setup(:default, options[:database] || ENV['DATABASE_URL'])
14
+ end
15
+
16
+ require "tentd/notifications/#{options[:job_backend] || 'girl_friday'}"
17
+
18
+ @faraday_adapter = options[:faraday_adapter]
19
+ API.new
20
+ end
21
+
22
+ def self.faraday_adapter
23
+ @faraday_adapter
24
+ end
25
+
26
+ def self.faraday_adapter=(a)
27
+ @faraday_adapter = a
28
+ end
29
+ end
30
+
31
+ require 'tentd/model'
@@ -0,0 +1,58 @@
1
+ module TentD
2
+ class API
3
+ PER_PAGE = 50
4
+ MAX_PER_PAGE = 200
5
+ MEDIA_TYPE = 'application/vnd.tent.v0+json'.freeze
6
+ PROFILE_REL = 'https://tent.io/rels/profile'.freeze
7
+
8
+ autoload :Apps, 'tentd/api/apps'
9
+ autoload :Posts, 'tentd/api/posts'
10
+ autoload :Groups, 'tentd/api/groups'
11
+ autoload :Profile, 'tentd/api/profile'
12
+ autoload :Followers, 'tentd/api/followers'
13
+ autoload :Followings, 'tentd/api/followings'
14
+ autoload :CoreProfileData, 'tentd/api/core_profile_data'
15
+ autoload :UserLookup, 'tentd/api/user_lookup'
16
+ autoload :AuthenticationLookup, 'tentd/api/authentication_lookup'
17
+ autoload :AuthenticationVerification, 'tentd/api/authentication_verification'
18
+ autoload :AuthenticationFinalize, 'tentd/api/authentication_finalize'
19
+ autoload :Authorization, 'tentd/api/authorization'
20
+ autoload :Authorizable, 'tentd/api/authorizable'
21
+ autoload :Router, 'tentd/api/router'
22
+ autoload :Middleware, 'tentd/api/middleware'
23
+ include Router
24
+
25
+ mount Apps
26
+ mount Posts
27
+ mount Groups
28
+ mount Profile
29
+ mount Followers
30
+ mount Followings
31
+
32
+ class HelloWorld < Middleware
33
+ def action(env)
34
+ [200, { 'Link' => %(<%s>; rel="%s") % [File.join(env['SCRIPT_NAME'], 'profile'), PROFILE_REL] }, ['Tent!']]
35
+ end
36
+ end
37
+
38
+ class CorsPreflight < Middleware
39
+ def action(env)
40
+ headers = {
41
+ 'Access-Control-Allow-Origin' => '*',
42
+ 'Access-Control-Allow-Methods' => 'GET, POST, HEAD, PUT, DELETE, PATCH, OPTIONS',
43
+ 'Access-Control-Allow-Headers' => 'Authorization',
44
+ 'Access-Control-Max-Age' => '2592000' # 30 days
45
+ }
46
+ [200, headers, []]
47
+ end
48
+ end
49
+
50
+ get '/' do |b|
51
+ b.use HelloWorld
52
+ end
53
+
54
+ options %r{/.*} do |b|
55
+ b.use CorsPreflight
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,196 @@
1
+ module TentD
2
+ class API
3
+ class Apps
4
+ include Router
5
+
6
+ class GetActualId < Middleware
7
+ def action(env)
8
+ if env.params.app_id
9
+ if app = Model::App.first(:public_id => env.params.app_id)
10
+ env.params.app_id = app.id
11
+ else
12
+ env.params.app_id = nil
13
+ end
14
+ end
15
+
16
+ if env.params.auth_id
17
+ if app_auth = Model::AppAuthorization.first(:public_id => env.params.auth_id)
18
+ env.params.auth_id = app_auth.id
19
+ else
20
+ env.params.auth_id = nil
21
+ end
22
+ end
23
+
24
+ env
25
+ end
26
+ end
27
+
28
+ class AuthorizeReadOne < Middleware
29
+ def action(env)
30
+ authorize_env!(env, :read_apps) unless env.params.app_id && env.current_auth &&
31
+ env.current_auth.kind_of?(Model::App) &&
32
+ env.current_auth.id == env.params.app_id
33
+ env
34
+ end
35
+ end
36
+
37
+ class AuthorizeReadAll < Middleware
38
+ def action(env)
39
+ authorize_env!(env, :read_apps)
40
+ env
41
+ end
42
+ end
43
+
44
+ class AuthorizeWriteOne < Middleware
45
+ def action(env)
46
+ authorize_env!(env, :write_apps) unless env.params.app_id && env.current_auth &&
47
+ env.current_auth.kind_of?(Model::App) &&
48
+ env.current_auth.id == env.params.app_id
49
+ env
50
+ end
51
+ end
52
+
53
+ class GetOne < Middleware
54
+ def action(env)
55
+ if app = Model::App.first(:id => env.params.app_id)
56
+ env.response = app
57
+ end
58
+ env
59
+ end
60
+ end
61
+
62
+ class GetAll < Middleware
63
+ def action(env)
64
+ env.response = Model::App.all
65
+ env
66
+ end
67
+ end
68
+
69
+ class Create < Middleware
70
+ def action(env)
71
+ env.response = Model::App.create_from_params(env.params.data)
72
+ env.authorized_scopes << :read_secrets
73
+ env
74
+ end
75
+ end
76
+
77
+ class CreateAuthorization < Middleware
78
+ def action(env)
79
+ unless authorize_env?(env, :write_apps)
80
+ if env.params.data.code
81
+ return AuthorizationTokenExchange.new(@app).call(env)
82
+ else
83
+ authorize_env!(env, :write_apps)
84
+ end
85
+ end
86
+
87
+ if app = Model::App.first(:id => env.params.app_id)
88
+ env.authorized_scopes << :authorization_token
89
+ authorization = app.authorizations.create_from_params(
90
+ :app_id => env.params.app_id,
91
+ :notification_url => env.params.data.notification_url,
92
+ :post_types => env.params.data.post_types.to_a.map { |url| URI.decode(url) },
93
+ :profile_info_types => env.params.data.profile_info_types.to_a.map { |url| URI.decode(url) },
94
+ :scopes => env.params.data.scopes
95
+ )
96
+ env.response = authorization
97
+ end
98
+ env
99
+ end
100
+ end
101
+
102
+ class AuthorizationTokenExchange < Middleware
103
+ def action(env)
104
+ if authorization = Model::AppAuthorization.first(:app_id => env.params.app_id, :token_code => env.params.data.code)
105
+ env.response = authorization.token_exchange!
106
+ else
107
+ raise Unauthorized
108
+ end
109
+ env
110
+ end
111
+ end
112
+
113
+ class Update < Middleware
114
+ def action(env)
115
+ if app = Model::App.update_from_params(env.params.app_id, env.params.data)
116
+ env.response = app
117
+ end
118
+ env
119
+ end
120
+ end
121
+
122
+ class UpdateAppAuthorization < Middleware
123
+ def action(env)
124
+ authorize_env!(env, :write_apps)
125
+ if (auth = TentD::Model::AppAuthorization.first(:app_id => env.params.app_id, :id => env.params.auth_id)) &&
126
+ auth.update_from_params(env.params.data)
127
+ env.response = auth
128
+ end
129
+ env
130
+ end
131
+ end
132
+
133
+ class Destroy < Middleware
134
+ def action(env)
135
+ if (app = Model::App.get(env.params.app_id)) && app.destroy
136
+ env.response = ''
137
+ end
138
+ env
139
+ end
140
+ end
141
+
142
+ class DestroyAppAuthorization < Middleware
143
+ def action(env)
144
+ authorize_env!(env, :write_apps)
145
+ if (auth = TentD::Model::AppAuthorization.first(:app_id => env.params.app_id, :id => env.params.auth_id)) &&
146
+ auth.destroy
147
+ env.response = ''
148
+ end
149
+ env
150
+ end
151
+ end
152
+
153
+ get '/apps/:app_id' do |b|
154
+ b.use GetActualId
155
+ b.use AuthorizeReadOne
156
+ b.use GetOne
157
+ end
158
+
159
+ get '/apps' do |b|
160
+ b.use AuthorizeReadAll
161
+ b.use GetAll
162
+ end
163
+
164
+ post '/apps' do |b|
165
+ b.use Create
166
+ end
167
+
168
+ post '/apps/:app_id/authorizations' do |b|
169
+ b.use GetActualId
170
+ b.use CreateAuthorization
171
+ end
172
+
173
+ put '/apps/:app_id/authorizations/:auth_id' do |b|
174
+ b.use GetActualId
175
+ b.use UpdateAppAuthorization
176
+ end
177
+
178
+ delete '/apps/:app_id/authorizations/:auth_id' do |b|
179
+ b.use GetActualId
180
+ b.use DestroyAppAuthorization
181
+ end
182
+
183
+ put '/apps/:app_id' do |b|
184
+ b.use GetActualId
185
+ b.use AuthorizeWriteOne
186
+ b.use Update
187
+ end
188
+
189
+ delete '/apps/:app_id' do |b|
190
+ b.use GetActualId
191
+ b.use AuthorizeWriteOne
192
+ b.use Destroy
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,12 @@
1
+ module TentD
2
+ class API
3
+ class AuthenticationFinalize < Middleware
4
+ def action(env)
5
+ return env unless env.hmac? && env.hmac.verified
6
+ env.current_auth = env.potential_auth
7
+ env.current_auth.update(:mac_timestamp_delta => Time.now.to_i - env.hmac.ts.to_i) unless env.current_auth.mac_timestamp_delta
8
+ env
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ module TentD
2
+ class API
3
+ class AuthenticationLookup < Middleware
4
+ def action(env)
5
+ return env unless env['HTTP_AUTHORIZATION']
6
+ env['hmac'] = Hash[env['HTTP_AUTHORIZATION'].scan(/([a-z]+)="([^"]+)"/i)]
7
+ mac_key_id = env['hmac']['id']
8
+ env.potential_auth = case mac_key_id.to_s[0,1]
9
+ when 's'
10
+ TentD::Model::Follower.first(:mac_key_id => mac_key_id)
11
+ when 'a'
12
+ TentD::Model::App.first(:mac_key_id => mac_key_id)
13
+ when 'u'
14
+ TentD::Model::AppAuthorization.first(:mac_key_id => mac_key_id)
15
+ end
16
+ env.potential_auth = Model::Following.first(:mac_key_id => mac_key_id) unless env.potential_auth
17
+ if env.potential_auth
18
+ env.hmac.secret = env.potential_auth.mac_key
19
+ env.hmac.algorithm = env.potential_auth.mac_algorithm
20
+ else
21
+ env.hmac = nil
22
+ end
23
+ env
24
+ end
25
+ end
26
+ end
27
+ end