tpitale-rack-oauth2-server 2.2.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.
- data/CHANGELOG +202 -0
- data/Gemfile +16 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +604 -0
- data/Rakefile +90 -0
- data/VERSION +1 -0
- data/bin/oauth2-server +206 -0
- data/lib/rack-oauth2-server.rb +4 -0
- data/lib/rack/oauth2/admin/css/screen.css +347 -0
- data/lib/rack/oauth2/admin/images/loading.gif +0 -0
- data/lib/rack/oauth2/admin/images/oauth-2.png +0 -0
- data/lib/rack/oauth2/admin/js/application.coffee +220 -0
- data/lib/rack/oauth2/admin/js/jquery.js +166 -0
- data/lib/rack/oauth2/admin/js/jquery.tmpl.js +414 -0
- data/lib/rack/oauth2/admin/js/protovis-r3.2.js +277 -0
- data/lib/rack/oauth2/admin/js/sammy.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.json.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.oauth2.js +142 -0
- data/lib/rack/oauth2/admin/js/sammy.storage.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.title.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.tmpl.js +5 -0
- data/lib/rack/oauth2/admin/js/underscore.js +722 -0
- data/lib/rack/oauth2/admin/views/client.tmpl +58 -0
- data/lib/rack/oauth2/admin/views/clients.tmpl +52 -0
- data/lib/rack/oauth2/admin/views/edit.tmpl +80 -0
- data/lib/rack/oauth2/admin/views/index.html +39 -0
- data/lib/rack/oauth2/admin/views/no_access.tmpl +4 -0
- data/lib/rack/oauth2/models.rb +27 -0
- data/lib/rack/oauth2/models/access_grant.rb +54 -0
- data/lib/rack/oauth2/models/access_token.rb +129 -0
- data/lib/rack/oauth2/models/auth_request.rb +61 -0
- data/lib/rack/oauth2/models/client.rb +93 -0
- data/lib/rack/oauth2/rails.rb +105 -0
- data/lib/rack/oauth2/server.rb +458 -0
- data/lib/rack/oauth2/server/admin.rb +250 -0
- data/lib/rack/oauth2/server/errors.rb +104 -0
- data/lib/rack/oauth2/server/helper.rb +147 -0
- data/lib/rack/oauth2/server/practice.rb +79 -0
- data/lib/rack/oauth2/server/railtie.rb +24 -0
- data/lib/rack/oauth2/server/utils.rb +30 -0
- data/lib/rack/oauth2/sinatra.rb +71 -0
- data/rack-oauth2-server.gemspec +24 -0
- data/rails/init.rb +11 -0
- data/test/admin/api_test.rb +228 -0
- data/test/admin/ui_test.rb +38 -0
- data/test/oauth/access_grant_test.rb +276 -0
- data/test/oauth/access_token_test.rb +311 -0
- data/test/oauth/authorization_test.rb +298 -0
- data/test/oauth/server_methods_test.rb +292 -0
- data/test/rails2/app/controllers/api_controller.rb +40 -0
- data/test/rails2/app/controllers/application_controller.rb +2 -0
- data/test/rails2/app/controllers/oauth_controller.rb +17 -0
- data/test/rails2/config/environment.rb +19 -0
- data/test/rails2/config/environments/test.rb +0 -0
- data/test/rails2/config/routes.rb +13 -0
- data/test/rails3/app/controllers/api_controller.rb +40 -0
- data/test/rails3/app/controllers/application_controller.rb +2 -0
- data/test/rails3/app/controllers/oauth_controller.rb +17 -0
- data/test/rails3/config/application.rb +19 -0
- data/test/rails3/config/environment.rb +2 -0
- data/test/rails3/config/routes.rb +12 -0
- data/test/setup.rb +120 -0
- data/test/sinatra/my_app.rb +69 -0
- metadata +145 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
<div class="client">
|
2
|
+
<div class="details">
|
3
|
+
<h2 class="name">{{if imageUrl}}<img src="${imageUrl}">{{/if}} ${displayName}</h2>
|
4
|
+
<div class="actions">
|
5
|
+
<a href="#/client/${id}/edit" rel="edit">Edit</a>
|
6
|
+
{{if !revoked}}
|
7
|
+
<a href="#/client/${id}/revoke" data-method="post" data-confirm="There is no undo. Are you really really sure?" rel="revoke">Revoke</a>
|
8
|
+
{{/if}}
|
9
|
+
<a href="#/client/${id}" data-method="delete" data-confirm="There is no undo. Are you really really sure?" rel="delete">Delete</a>
|
10
|
+
</div>
|
11
|
+
<div class="meta">Site: <a href="${link}">${link}</a></div>
|
12
|
+
<div class="meta">
|
13
|
+
Created {{html $.shortdate(revoked)}}
|
14
|
+
{{if revoked}}Revoked {{html $.shortdate(revoked)}}{{/if}}
|
15
|
+
</div>
|
16
|
+
{{each notes}}<p class="notes">${this}</p>{{/each}}
|
17
|
+
</div>
|
18
|
+
<div class="metrics">
|
19
|
+
<div id="fig"></div>
|
20
|
+
<ul class="badges">
|
21
|
+
<li title="Access tokens granted, lifetime total"><big>${$.thousands(tokens.total)}</big><small>Granted</small></li>
|
22
|
+
<li title="Access tokens granted, last 7 days"><big>${$.thousands(tokens.week)}</big><small>This Week</small></li>
|
23
|
+
<li title="Access tokens revoked, last 7 days"><big>${$.thousands(tokens.revoked)}</big><small>Revoked (Week)</small></li>
|
24
|
+
</ul>
|
25
|
+
</div>
|
26
|
+
<table class="tokens">
|
27
|
+
<thead>
|
28
|
+
<th>Token</th>
|
29
|
+
<th>Identity</th>
|
30
|
+
<th>Scope</th>
|
31
|
+
<th>Created</th>
|
32
|
+
<th>Accessed</th>
|
33
|
+
<th>Revoked</th>
|
34
|
+
</thead>
|
35
|
+
<tbody>
|
36
|
+
{{each tokens.list}}
|
37
|
+
<tr>
|
38
|
+
<td class="token">${token}</td>
|
39
|
+
<td class="identity">{{if link}}<a href="${link}">${identity}</a>{{else}}${identity}{{/if}}</td>
|
40
|
+
<td class="scope">${scope}</td>
|
41
|
+
<td class="created">{{html $.shortdate(created)}}</td>
|
42
|
+
<td class="accessed">{{if last_access}}{{html $.shortdate(last_access)}}{{/if}}</td>
|
43
|
+
<td class="revoke">
|
44
|
+
{{if revoked}}
|
45
|
+
{{html $.shortdate(revoked)}}
|
46
|
+
{{else}}
|
47
|
+
<a href="#/token/${token}/revoke" data-method="post" data-confirm="Are you sure?" rel="revoke">Revoke</a>
|
48
|
+
{{/if}}
|
49
|
+
</td>
|
50
|
+
</tr>
|
51
|
+
{{/each}}
|
52
|
+
</tbody>
|
53
|
+
</table>
|
54
|
+
<div class="pagination">
|
55
|
+
{{if tokens.previous}}<a href="#/client/${id}/page/${tokens.page - 1}" rel="previous">Previous</a>{{/if}}
|
56
|
+
{{if tokens.next}}<a href="#/client/${id}/page/${tokens.page + 1}" rel="next">Next</a>{{/if}}
|
57
|
+
</div>
|
58
|
+
</div>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<div class="client">
|
2
|
+
<div class="metrics">
|
3
|
+
<div id="fig"></div>
|
4
|
+
<ul class="badges">
|
5
|
+
<li title="Access tokens granted, lifetime total"><big>${$.thousands(tokens.total)}</big><small>Granted</small></li>
|
6
|
+
<li title="Access tokens granted, last 7 days"><big>${$.thousands(tokens.week)}</big><small>This Week</small></li>
|
7
|
+
<li title="Access tokens revoked, last 7 days"><big>${$.thousands(tokens.revoked)}</big><small>Revoked (Week)</small></li>
|
8
|
+
</ul>
|
9
|
+
</div>
|
10
|
+
<a href="#/new" style="float:left">Add New Client</a>
|
11
|
+
<table class="clients">
|
12
|
+
<thead>
|
13
|
+
<th>Application</th>
|
14
|
+
<th>ID/Secret</th>
|
15
|
+
<th>Created</th>
|
16
|
+
<th>Revoked</th>
|
17
|
+
</thead>
|
18
|
+
{{each clients}}
|
19
|
+
<tr class="${revoked ? "revoked" : "active"}">
|
20
|
+
<td class="name">
|
21
|
+
<a href="#/client/${id}">
|
22
|
+
{{if imageUrl}}<img src="${imageUrl}">{{/if}}
|
23
|
+
${displayName.trim() == "" ? "untitled" : displayName}
|
24
|
+
</a>
|
25
|
+
</td>
|
26
|
+
<td class="secrets">
|
27
|
+
<a href="" rel="toggle">Reveal</a>
|
28
|
+
<dl>
|
29
|
+
<dt>ID</dt><dd>${id}</dd>
|
30
|
+
<dt>Secret</dt><dd>${secret}</dd>
|
31
|
+
<dt>Redirect</dt><dd>${redirectUri}</dd>
|
32
|
+
</dl>
|
33
|
+
</td>
|
34
|
+
<td class="created">{{html $.shortdate(created)}}</td>
|
35
|
+
<td class="revoke">{{if revoked}}{{html $.shortdate(revoked)}}{{/if}}</td>
|
36
|
+
</tr>
|
37
|
+
{{/each}}
|
38
|
+
</table>
|
39
|
+
</div>
|
40
|
+
<script type="text/javascript">
|
41
|
+
$("td.secrets a[rel=toggle]").click(function(evt) {
|
42
|
+
evt.preventDefault();
|
43
|
+
var dl = $(this).next("dl");
|
44
|
+
if (dl.is(":visible")) {
|
45
|
+
$(this).html("Reveal");
|
46
|
+
dl.hide();
|
47
|
+
} else {
|
48
|
+
$(this).html("Hide");
|
49
|
+
dl.show();
|
50
|
+
}
|
51
|
+
});
|
52
|
+
</script>
|
@@ -0,0 +1,80 @@
|
|
1
|
+
{{if id}}<form action="#/client/${id}" method="put" class="client edit">
|
2
|
+
{{else}}<form action="#/clients" method="post" class="client new">{{/if}}
|
3
|
+
<div class="fields">
|
4
|
+
<h2>Identification</h2>
|
5
|
+
<img id="image">
|
6
|
+
<label>Display Name
|
7
|
+
<input type="text" name="displayName" value="${displayName}" size="70" required autofocus>
|
8
|
+
<p class="hint">This is the application name that users see when asked to authorize.</p>
|
9
|
+
</label>
|
10
|
+
<label>Site URL
|
11
|
+
<input type="url" name="link" value="${link}" size="70" required>
|
12
|
+
<p class="hint">This is a link to the application's site.</p>
|
13
|
+
</label>
|
14
|
+
<label>Image URL
|
15
|
+
<input type="url" name="imageUrl" value="${imageUrl}" size="70">
|
16
|
+
<p class="hint">This is a link to the application's icon (48x48).</p>
|
17
|
+
</label>
|
18
|
+
<label>Redirect URI
|
19
|
+
<input type="url" name="redirectUri" value="${redirectUri}" size="70" required>
|
20
|
+
<p class="hint">Users redirected back to this URL on successful authorization.</p>
|
21
|
+
</label>
|
22
|
+
<label>Notes
|
23
|
+
<textarea name="notes" cols="50" rows="5">${notes}</textarea>
|
24
|
+
<p class="hint">For internal use.</p>
|
25
|
+
</label>
|
26
|
+
{{if id}}<button>Save Changes</button>
|
27
|
+
{{else}}<button>Create Client</button>{{/if}}
|
28
|
+
</div>
|
29
|
+
<div class="scope">
|
30
|
+
<h2>Scope</h2>
|
31
|
+
{{each common}}
|
32
|
+
<label class="check"><input type="checkbox" name="scope" value="${this}" ${scope.indexOf(this.toString()) < 0 ? null : "checked"}>${this}</label>
|
33
|
+
{{/each}}
|
34
|
+
{{each scope}}
|
35
|
+
{{if common.indexOf(this.toString()) < 0}}
|
36
|
+
<label class="check uncommon"><input type="checkbox" name="scope" value="${this}" checked>${this}</label>
|
37
|
+
{{/if}}
|
38
|
+
{{/each}}
|
39
|
+
<label>Uncommon
|
40
|
+
<input type="text" name="scope" value="" size="35">
|
41
|
+
<p class="hint">Space separated list of uncommon scope.</p>
|
42
|
+
</label>
|
43
|
+
</div>
|
44
|
+
<hr>
|
45
|
+
</form>
|
46
|
+
<script type="text/javascript">
|
47
|
+
$(function() {
|
48
|
+
var image = $("#image");
|
49
|
+
image.load(function() {
|
50
|
+
image.show().removeClass("loading");
|
51
|
+
}).error(function() {
|
52
|
+
if (image.attr("src"))
|
53
|
+
image.removeClass("loading");
|
54
|
+
});
|
55
|
+
|
56
|
+
var imageUrl = $("input[name=imageUrl]");
|
57
|
+
imageUrl.change(function() {
|
58
|
+
var url = $(this).val().trim();
|
59
|
+
if (url == "") {
|
60
|
+
image.hide();
|
61
|
+
} else {
|
62
|
+
image.attr("src", "admin/images/loading.gif").show().addClass("loading");
|
63
|
+
setTimeout(function() { image.attr("src", url); }, 10);
|
64
|
+
}
|
65
|
+
}).trigger("change");
|
66
|
+
|
67
|
+
$("input[name=link]").change(function() {
|
68
|
+
if (imageUrl.val().trim() == "") {
|
69
|
+
$("#image").show().addClass("loading").attr("src", null);
|
70
|
+
var image = new Image();
|
71
|
+
image.src = $(this).val().trim().replace(/^(https?:\/\/)(.+?)(\/.*|$)/, "$1$2/favicon.ico");
|
72
|
+
image.onload = function() {
|
73
|
+
if (imageUrl.val().trim() == "") {
|
74
|
+
imageUrl.val(image.src).trigger("change");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
});
|
79
|
+
})
|
80
|
+
</script>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>OAuth Console</title>
|
5
|
+
<link href="admin/css/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
|
6
|
+
<script src="admin/js/jquery.js" type="text/javascript"></script>
|
7
|
+
<script src="admin/js/jquery.tmpl.js" type="text/javascript"></script>
|
8
|
+
<script src="admin/js/sammy.js" type="text/javascript"></script>
|
9
|
+
<script src="admin/js/sammy.tmpl.js" type="text/javascript"></script>
|
10
|
+
<script src="admin/js/sammy.json.js" type="text/javascript"></script>
|
11
|
+
<script src="admin/js/sammy.storage.js" type="text/javascript"></script>
|
12
|
+
<script src="admin/js/sammy.title.js" type="text/javascript"></script>
|
13
|
+
<script src="admin/js/sammy.oauth2.js" type="text/javascript"></script>
|
14
|
+
<script src="admin/js/underscore.js" type="text/javascript"></script>
|
15
|
+
<script src="admin/js/protovis-r3.2.js" type="text/javascript"></script>
|
16
|
+
<script src="admin/js/application.js" type="text/javascript"></script>
|
17
|
+
<link rel="shortcut icon" href="admin/images/oauth-2.png">
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="notice" style="display:none"></div>
|
21
|
+
<div id="header">
|
22
|
+
<div class="title">
|
23
|
+
<a href="#/"><img src="admin/images/oauth-2.png"> OAuth Console</a>
|
24
|
+
</div>
|
25
|
+
<a href="admin/authorize" class="signin">Sign in</a>
|
26
|
+
<a href="#/signout" class="signout">Sign out</a>
|
27
|
+
</div>
|
28
|
+
<div id="throbber" class="loading"></div>
|
29
|
+
<div id="main"></div>
|
30
|
+
<div id="footer">
|
31
|
+
<p>Powered by <a href="http://github.com/flowtown/rack-oauth2-server">Rack::OAuth2::Server</a></p>
|
32
|
+
</div>
|
33
|
+
<script>
|
34
|
+
var loading = new Image();
|
35
|
+
loading.src = "admin/images/loading.gif";
|
36
|
+
$(function() { Sammy("#main").run("#/"); });
|
37
|
+
</script>
|
38
|
+
</body>
|
39
|
+
</html>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# require "mongo"
|
2
|
+
require "openssl"
|
3
|
+
require "rack/oauth2/server/errors"
|
4
|
+
require "rack/oauth2/server/utils"
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
module OAuth2
|
8
|
+
class Server
|
9
|
+
# class << self
|
10
|
+
# # unused!
|
11
|
+
# attr_accessor :database
|
12
|
+
# end
|
13
|
+
|
14
|
+
# Long, random and hexy.
|
15
|
+
def self.secure_random
|
16
|
+
OpenSSL::Random.random_bytes(32).unpack("H*")[0]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
require "rack/oauth2/models/client"
|
24
|
+
require "rack/oauth2/models/auth_request"
|
25
|
+
require "rack/oauth2/models/access_grant"
|
26
|
+
require "rack/oauth2/models/access_token"
|
27
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
class Server
|
4
|
+
|
5
|
+
# The access grant is a nonce, new grant created each time we need it and
|
6
|
+
# good for redeeming one access token.
|
7
|
+
class AccessGrant < ActiveRecord::Base
|
8
|
+
belongs_to :client, :class_name => 'Rack::OAuth2::Server::Client'
|
9
|
+
|
10
|
+
# Find AccessGrant from authentication code.
|
11
|
+
def self.from_code(code)
|
12
|
+
first(:conditions => {:code => code, :revoked => nil})
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create a new access grant.
|
16
|
+
def self.create(identity, client, scope, redirect_uri = nil, expires = nil)
|
17
|
+
raise ArgumentError, "Identity must be String or Integer" unless String === identity || Integer === identity
|
18
|
+
scope = Utils.normalize_scope(scope) & Utils.normalize_scope(client.scope) # Only allowed scope
|
19
|
+
expires_at = Time.now.to_i + (expires || 300)
|
20
|
+
|
21
|
+
attributes = {
|
22
|
+
:code => Server.secure_random,
|
23
|
+
:identity=>identity,
|
24
|
+
:scope=>scope,
|
25
|
+
:client_id=>client.id,
|
26
|
+
:redirect_uri=>client.redirect_uri || redirect_uri,
|
27
|
+
:created_at=>Time.now.to_i,
|
28
|
+
:expires_at=>expires_at
|
29
|
+
}
|
30
|
+
|
31
|
+
super(attributes)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Authorize access and return new access token.
|
35
|
+
#
|
36
|
+
# Access grant can only be redeemed once, but client can make multiple
|
37
|
+
# requests to obtain it, so we need to make sure only first request is
|
38
|
+
# successful in returning access token, futher requests raise
|
39
|
+
# InvalidGrantError.
|
40
|
+
def authorize!
|
41
|
+
raise InvalidGrantError, "You can't use the same access grant twice" if self.access_token || self.revoked
|
42
|
+
access_token = AccessToken.get_token_for(identity, client, scope)
|
43
|
+
update_attributes(:access_token => access_token.token, :granted_at => Time.now)
|
44
|
+
access_token
|
45
|
+
end
|
46
|
+
|
47
|
+
def revoke!
|
48
|
+
update_attributes(:revoked => Time.now)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
class Server
|
4
|
+
|
5
|
+
# Access token. This is what clients use to access resources.
|
6
|
+
#
|
7
|
+
# An access token is a unique code, associated with a client, an identity
|
8
|
+
# and scope. It may be revoked, or expire after a certain period.
|
9
|
+
class AccessToken < ActiveRecord::Base
|
10
|
+
belongs_to :client, :class_name => 'Rack::OAuth2::Server::Client' # counter_cache?
|
11
|
+
|
12
|
+
# Creates a new AccessToken for the given client and scope.
|
13
|
+
def self.create_token_for(client, scope)
|
14
|
+
scope = Utils.normalize_scope(scope) & Utils.normalize_scope(client.scope) # Only allowed scope
|
15
|
+
|
16
|
+
attributes = {
|
17
|
+
:code => Server.secure_random,
|
18
|
+
:scope => scope,
|
19
|
+
:client => client
|
20
|
+
}
|
21
|
+
|
22
|
+
create(attributes)
|
23
|
+
|
24
|
+
# Client.collection.update({ :_id=>client.id }, { :$inc=>{ :tokens_granted=>1 } })
|
25
|
+
# Server.new_instance self, token
|
26
|
+
end
|
27
|
+
|
28
|
+
# Find AccessToken from token. Does not return revoked tokens.
|
29
|
+
def self.from_token(token) # token == code??
|
30
|
+
first(:conditions => {:code => token, :revoked => nil})
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get an access token (create new one if necessary).
|
34
|
+
def self.get_token_for(identity, client, scope)
|
35
|
+
raise ArgumentError, "Identity must be String or Integer" unless String === identity || Integer === identity
|
36
|
+
scope = Utils.normalize_scope(scope) & Utils.normalize_scope(client.scope) # Only allowed scope
|
37
|
+
|
38
|
+
token = first(:conditions => {:identity=>identity, :scope=>scope, :client_id=>client.id, :revoked=>nil})
|
39
|
+
|
40
|
+
token ||= begin
|
41
|
+
attributes = {
|
42
|
+
:code => Server.secure_random,
|
43
|
+
:identity => identity,
|
44
|
+
:scope => scope,
|
45
|
+
:client_id => client.id
|
46
|
+
}
|
47
|
+
|
48
|
+
create(attributes)
|
49
|
+
# Client.collection.update({ :_id=>client.id }, { :$inc=>{ :tokens_granted=>1 } })
|
50
|
+
end
|
51
|
+
|
52
|
+
token
|
53
|
+
end
|
54
|
+
|
55
|
+
alias_attribute :token, :code
|
56
|
+
|
57
|
+
# Find all AccessTokens for an identity.
|
58
|
+
def self.from_identity(identity)
|
59
|
+
all(:condition => {:identity => identity})
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns all access tokens for a given client, Use limit and offset
|
63
|
+
# to return a subset of tokens, sorted by creation date.
|
64
|
+
def self.for_client(client_id, offset = 0, limit = 100)
|
65
|
+
all(:conditions => {:client_id => client.id}, :offset => offset, :limit => limit, :order => :created_at)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns count of access tokens.
|
69
|
+
#
|
70
|
+
# @param [Hash] filter Count only a subset of access tokens
|
71
|
+
# @option filter [Integer] days Only count that many days (since now)
|
72
|
+
# @option filter [Boolean] revoked Only count revoked (true) or non-revoked (false) tokens; count all tokens if nil
|
73
|
+
# @option filter [String, ObjectId] client_id Only tokens grant to this client
|
74
|
+
def self.count(filter = {})
|
75
|
+
conditions = []
|
76
|
+
if filter[:days]
|
77
|
+
now = Time.now
|
78
|
+
start_time = now - (filter[:days] * 86400)
|
79
|
+
|
80
|
+
key = filter[:revoked] ? 'revoked' : 'created_at'
|
81
|
+
conditions = ["#{key} > ? AND #{key} <= ?", start_time, now]
|
82
|
+
elsif filter.has_key?(:revoked)
|
83
|
+
conditions = ["revoked " + (filter[:revoked] ? "IS NOT NULL" : "IS NULL")]
|
84
|
+
end
|
85
|
+
|
86
|
+
if filter.has_key?(:client_id)
|
87
|
+
conditions.first = conditions.empty? ? "client_id = ?" : " AND client_id = ?"
|
88
|
+
conditions << filter[:client_id]
|
89
|
+
end
|
90
|
+
|
91
|
+
super(:conditions => conditions)
|
92
|
+
end
|
93
|
+
|
94
|
+
# def self.historical(filter = {})
|
95
|
+
# # days = filter[:days] || 60
|
96
|
+
# # select = { :$gt=> { :created_at=>Time.now - 86400 * days } }
|
97
|
+
# # select = {}
|
98
|
+
#
|
99
|
+
# if filter.has_key?(:client_id)
|
100
|
+
# conditions << "client_id = ?" << filter[:client_id]
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# raw = Server::AccessToken.collection.group("function (token) { return { ts: Math.floor(token.created_at / 86400) } }",
|
104
|
+
# select, { :granted=>0 }, "function (token, state) { state.granted++ }")
|
105
|
+
# raw.sort { |a, b| a["ts"] - b["ts"] }
|
106
|
+
# end
|
107
|
+
|
108
|
+
# Updates the last access timestamp.
|
109
|
+
def access!
|
110
|
+
today = (Time.now.to_i / 3600) * 3600
|
111
|
+
if last_access.nil? || last_access < today
|
112
|
+
AccessToken.update_all({:last_access=>today, :prev_access=>last_access}, {:code => code})
|
113
|
+
reload
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Revokes this access token.
|
118
|
+
def revoke!
|
119
|
+
revoked = Time.now
|
120
|
+
AccessToken.update_all({:revoked=>revoked}, {:id => id})
|
121
|
+
reload
|
122
|
+
|
123
|
+
# Client.collection.update({ :_id=>client_id }, { :$inc=>{ :tokens_revoked=>1 } })
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|