server-side storage model
First pass at a server-side storage model. New tables for consumers, tokens, and nonces, with associated classes. An OAuthDataStore class interfaces with the OAuth.php library to enable server logic. Some additional work to get pretty-OK random number generation into the utilities library. Use /dev/urandom if available; else use mt_rand(). darcs-hash:20080527200721-84dde-308c047af2ebc2c4d753c1e1e24af20fef862a7e.gz
This commit is contained in:
parent
90b4873a00
commit
9977591b78
23
classes/Consumer.php
Normal file
23
classes/Consumer.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for consumer
|
||||
*/
|
||||
require_once 'DB/DataObject.php';
|
||||
|
||||
class Consumer extends DB_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'consumer'; // table name
|
||||
public $consumer_key; // varchar(255) primary_key not_null
|
||||
public $seed; // char(32) not_null
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Consumer',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
}
|
25
classes/Nonce.php
Normal file
25
classes/Nonce.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for nonce
|
||||
*/
|
||||
require_once 'DB/DataObject.php';
|
||||
|
||||
class Nonce extends DB_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'nonce'; // table name
|
||||
public $consumer_key; // varchar(255) primary_key not_null
|
||||
public $tok; // char(32) primary_key not_null
|
||||
public $nonce; // char(32) primary_key not_null
|
||||
public $ts; // datetime() not_null
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Nonce',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
}
|
@ -33,6 +33,7 @@ class Subscription extends DB_DataObject
|
||||
public $subscriber; // int(4) primary_key not_null
|
||||
public $subscribed; // int(4) primary_key not_null
|
||||
public $token; // varchar(255)
|
||||
public $secret; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
|
26
classes/Token.php
Normal file
26
classes/Token.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for token
|
||||
*/
|
||||
require_once 'DB/DataObject.php';
|
||||
|
||||
class Token extends DB_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'token'; // table name
|
||||
public $consumer_key; // varchar(255) primary_key not_null
|
||||
public $tok; // char(32) primary_key not_null
|
||||
public $secret; // char(32) not_null
|
||||
public $type; // tinyint(1) not_null
|
||||
public $state; // tinyint(1)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Token',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
}
|
@ -16,6 +16,28 @@ width = K
|
||||
height = K
|
||||
url = U
|
||||
|
||||
[consumer]
|
||||
consumer_key = 130
|
||||
seed = 130
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[consumer__keys]
|
||||
consumer_key = K
|
||||
|
||||
[nonce]
|
||||
consumer_key = 130
|
||||
tok = 130
|
||||
nonce = 130
|
||||
ts = 142
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[nonce__keys]
|
||||
consumer_key = K
|
||||
tok = K
|
||||
nonce = K
|
||||
|
||||
[notice]
|
||||
id = 129
|
||||
profile_id = 129
|
||||
@ -58,6 +80,7 @@ uri = U
|
||||
subscriber = 129
|
||||
subscribed = 129
|
||||
token = 2
|
||||
secret = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
@ -65,6 +88,19 @@ modified = 384
|
||||
subscriber = K
|
||||
subscribed = K
|
||||
|
||||
[token]
|
||||
consumer_key = 130
|
||||
tok = 130
|
||||
secret = 130
|
||||
type = 145
|
||||
state = 17
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[token__keys]
|
||||
consumer_key = K
|
||||
tok = K
|
||||
|
||||
[user]
|
||||
id = 129
|
||||
nickname = 2
|
||||
|
@ -76,4 +76,40 @@ create table notice (
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
index notice_profile_id_idx (profile_id)
|
||||
);
|
||||
|
||||
/* tables for OAuth */
|
||||
|
||||
create table consumer (
|
||||
consumer_key varchar(255) primary key comment 'unique identifier, root URL',
|
||||
seed char(32) not null comment 'seed for new tokens by this consumer',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified'
|
||||
);
|
||||
|
||||
create table token (
|
||||
consumer_key varchar(255) not null comment 'unique identifier, root URL' references consumer (consumer_key),
|
||||
tok char(32) not null comment 'identifying value',
|
||||
secret char(32) not null comment 'secret value',
|
||||
type tinyint not null default 0 comment 'request or access',
|
||||
state tinyint default 0 comment 'for requests; 0 = initial, 1 = authorized, 2 = used',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
constraint primary key (consumer_key, tok)
|
||||
);
|
||||
|
||||
create table nonce (
|
||||
consumer_key varchar(255) not null comment 'unique identifier, root URL',
|
||||
tok char(32) not null comment 'identifying value',
|
||||
nonce char(32) not null comment 'nonce',
|
||||
ts datetime not null comment 'timestamp sent',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
constraint primary key (consumer_key, tok, nonce),
|
||||
constraint foreign key (consumer_key, tok) references token (consumer_key, tok)
|
||||
);
|
111
lib/oauthstore.php
Normal file
111
lib/oauthstore.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/lib/omb.php');
|
||||
|
||||
class LaconicaOAuthDataStore extends OAuthDataStore {
|
||||
|
||||
# We just keep a record of who's contacted us
|
||||
|
||||
function lookup_consumer($consumer_key) {
|
||||
$con = new Consumer('key', $consumer_key);
|
||||
if (!$con) {
|
||||
$con = new Consumer();
|
||||
$con->consumer_key = $consumer_key;
|
||||
$con->seed = common_good_rand(16);
|
||||
$con->created = DB_DataObject_Cast::dateTime();
|
||||
if (!$con->insert()) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return new OAuthConsumer($con->consumer_key, '');
|
||||
}
|
||||
|
||||
function lookup_token($consumer, $token_type, $token) {
|
||||
$t = new Token();
|
||||
$t->consumer_key = $consumer->consumer_key;
|
||||
$t->tok = $token;
|
||||
$t->type = ($token_type == 'access') ? 1 : 0;
|
||||
if ($t->find(true)) {
|
||||
return new OAuthToken($t->tok, $t->secret);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
|
||||
$n = new Nonce();
|
||||
$n->consumer_key = $consumer->consumer_key;
|
||||
$n->tok = $token;
|
||||
$n->nonce = $nonce;
|
||||
if ($n->find(TRUE)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
$n->timestamp = $timestamp;
|
||||
$n->created = DB_DataObject_Cast::dateTime();
|
||||
$n->insert();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_request_token($consumer) {
|
||||
$t = new Token();
|
||||
$t->consumer_key = $consumer->consumer_key;
|
||||
$t->tok = common_good_rand(16);
|
||||
$t->secret = common_good_rand(16);
|
||||
$t->type = 0; # request
|
||||
$t->state = 0;
|
||||
$t->created = DB_DataObject_Cast::dateTime();
|
||||
if (!$t->insert()) {
|
||||
return NULL;
|
||||
} else {
|
||||
return new OAuthToken($t->tok, $t->secret);
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_access_token($token, $consumer) {
|
||||
$rt = new Token();
|
||||
$rt->consumer_key = $consumer->consumer_key;
|
||||
$rt->tok = $token;
|
||||
if ($rt->find(TRUE) && $rt->state == 1) {
|
||||
$at = new Token();
|
||||
$at->consumer_key = $consumer->consumer_key;
|
||||
$at->tok = common_good_rand(16);
|
||||
$at->secret = common_good_rand(16);
|
||||
$at->type = 1; # access
|
||||
$at->created = DB_DataObject_Cast::dateTime();
|
||||
if (!$at->insert()) {
|
||||
return NULL;
|
||||
} else {
|
||||
# burn the old one
|
||||
$orig_rt = clone($rt);
|
||||
$rt->state = 2; # used
|
||||
if (!$rt->update($orig_rt)) {
|
||||
return NULL;
|
||||
} else {
|
||||
return new OAuthToken($at->tok, $at->secret);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
32
lib/util.php
32
lib/util.php
@ -447,6 +447,38 @@ function common_root_url() {
|
||||
return "http://".$config['site']['server'].'/'.$pathpart;
|
||||
}
|
||||
|
||||
# returns $bytes bytes of random data as a hexadecimal string
|
||||
# "good" here is a goal and not a guarantee
|
||||
|
||||
function common_good_rand($bytes) {
|
||||
# XXX: use random.org...?
|
||||
if (file_exists('/dev/urandom')) {
|
||||
return common_urandom($bytes);
|
||||
} else { # FIXME: this is probably not good enough
|
||||
return common_mtrand($bytes);
|
||||
}
|
||||
}
|
||||
|
||||
function common_urandom($bytes) {
|
||||
$h = fopen('/dev/urandom', 'rb');
|
||||
# should not block
|
||||
$src = fread($h, $bytes);
|
||||
fclose($h);
|
||||
$enc = '';
|
||||
for ($i = 0; $i < $bytes; $i++) {
|
||||
$enc .= sprintf("%02x", (ord($src[$i])));
|
||||
}
|
||||
return $enc;
|
||||
}
|
||||
|
||||
function common_mtrand($bytes) {
|
||||
$enc = '';
|
||||
for ($i = 0; $i < $bytes; $i++) {
|
||||
$enc .= sprintf("%02x", mt_rand(0, 255));
|
||||
}
|
||||
return $enc;
|
||||
}
|
||||
|
||||
// XXX: set up gettext
|
||||
|
||||
function _t($str) {
|
||||
|
Loading…
Reference in New Issue
Block a user