tpitale-rack-oauth2-server 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|