2008-06-18 14:26:38 +09:00
< ? 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/openid.php' );
2008-12-24 04:49:23 +09:00
class FinishopenidloginAction extends Action
{
2008-06-18 14:26:38 +09:00
2008-12-24 04:33:23 +09:00
function handle ( $args )
{
2008-12-24 04:19:07 +09:00
parent :: handle ( $args );
if ( common_logged_in ()) {
common_user_error ( _ ( 'Already logged in.' ));
} else if ( $_SERVER [ 'REQUEST_METHOD' ] == 'POST' ) {
$token = $this -> trimmed ( 'token' );
if ( ! $token || $token != common_session_token ()) {
$this -> show_form ( _ ( 'There was a problem with your session token. Try again, please.' ));
return ;
}
if ( $this -> arg ( 'create' )) {
if ( ! $this -> boolean ( 'license' )) {
$this -> show_form ( _ ( 'You can\'t register if you don\'t agree to the license.' ),
$this -> trimmed ( 'newname' ));
return ;
}
$this -> create_new_user ();
} else if ( $this -> arg ( 'connect' )) {
$this -> connect_user ();
} else {
common_debug ( print_r ( $this -> args , true ), __FILE__ );
$this -> show_form ( _ ( 'Something weird happened.' ),
$this -> trimmed ( 'newname' ));
}
} else {
$this -> try_login ();
}
}
2008-12-24 04:33:23 +09:00
function show_top ( $error = null )
{
2008-12-24 04:19:07 +09:00
if ( $error ) {
common_element ( 'div' , array ( 'class' => 'error' ), $error );
} else {
global $config ;
common_element ( 'div' , 'instructions' ,
sprintf ( _ ( 'This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.' ), $config [ 'site' ][ 'name' ]));
}
}
2008-12-24 04:33:23 +09:00
function show_form ( $error = null , $username = null )
{
2008-12-24 04:21:29 +09:00
common_show_header ( _ ( 'OpenID Account Setup' ), null , $error ,
2008-12-24 04:19:07 +09:00
array ( $this , 'show_top' ));
common_element_start ( 'form' , array ( 'method' => 'post' ,
'id' => 'account_connect' ,
'action' => common_local_url ( 'finishopenidlogin' )));
common_hidden ( 'token' , common_session_token ());
2008-12-24 04:21:29 +09:00
common_element ( 'h2' , null ,
2008-12-24 04:19:07 +09:00
_ ( 'Create new account' ));
2008-12-24 04:21:29 +09:00
common_element ( 'p' , null ,
2008-12-24 04:19:07 +09:00
_ ( 'Create a new user with this nickname.' ));
common_input ( 'newname' , _ ( 'New nickname' ),
( $username ) ? $username : '' ,
_ ( '1-64 lowercase letters or numbers, no punctuation or spaces' ));
common_element_start ( 'p' );
common_element ( 'input' , array ( 'type' => 'checkbox' ,
'id' => 'license' ,
'name' => 'license' ,
'value' => 'true' ));
common_text ( _ ( 'My text and files are available under ' ));
common_element ( 'a' , array ( href => common_config ( 'license' , 'url' )),
common_config ( 'license' , 'title' ));
common_text ( _ ( ' except this private data: password, email address, IM address, phone number.' ));
common_element_end ( 'p' );
common_submit ( 'create' , _ ( 'Create' ));
2008-12-24 04:21:29 +09:00
common_element ( 'h2' , null ,
2008-12-24 04:19:07 +09:00
_ ( 'Connect existing account' ));
2008-12-24 04:21:29 +09:00
common_element ( 'p' , null ,
2008-12-24 04:19:07 +09:00
_ ( 'If you already have an account, login with your username and password to connect it to your OpenID.' ));
common_input ( 'nickname' , _ ( 'Existing nickname' ));
common_password ( 'password' , _ ( 'Password' ));
common_submit ( 'connect' , _ ( 'Connect' ));
common_element_end ( 'form' );
common_show_footer ();
}
2008-12-24 04:33:23 +09:00
function try_login ()
{
2008-12-24 04:19:07 +09:00
$consumer = oid_consumer ();
$response = $consumer -> complete ( common_local_url ( 'finishopenidlogin' ));
if ( $response -> status == Auth_OpenID_CANCEL ) {
$this -> message ( _ ( 'OpenID authentication cancelled.' ));
return ;
} else if ( $response -> status == Auth_OpenID_FAILURE ) {
// Authentication failed; display the error message.
$this -> message ( sprintf ( _ ( 'OpenID authentication failed: %s' ), $response -> message ));
} else if ( $response -> status == Auth_OpenID_SUCCESS ) {
// This means the authentication succeeded; extract the
// identity URL and Simple Registration data (if it was
// returned).
$display = $response -> getDisplayIdentifier ();
$canonical = ( $response -> endpoint -> canonicalID ) ?
$response -> endpoint -> canonicalID : $response -> getDisplayIdentifier ();
$sreg_resp = Auth_OpenID_SRegResponse :: fromSuccessResponse ( $response );
if ( $sreg_resp ) {
$sreg = $sreg_resp -> contents ();
}
$user = oid_get_user ( $canonical );
if ( $user ) {
oid_set_last ( $display );
# XXX: commented out at @edd's request until better
# control over how data flows from OpenID provider.
# oid_update_user($user, $sreg);
common_set_user ( $user );
common_real_login ( true );
if ( isset ( $_SESSION [ 'openid_rememberme' ]) && $_SESSION [ 'openid_rememberme' ]) {
common_rememberme ( $user );
}
2008-12-10 03:03:30 +09:00
unset ( $_SESSION [ 'openid_rememberme' ]);
2008-12-24 04:19:07 +09:00
$this -> go_home ( $user -> nickname );
} else {
$this -> save_values ( $display , $canonical , $sreg );
2008-12-24 04:21:29 +09:00
$this -> show_form ( null , $this -> best_new_nickname ( $display , $sreg ));
2008-12-24 04:19:07 +09:00
}
}
}
2008-12-24 04:33:23 +09:00
function message ( $msg )
{
2008-12-24 04:19:07 +09:00
common_show_header ( _ ( 'OpenID Login' ));
2008-12-24 04:21:29 +09:00
common_element ( 'p' , null , $msg );
2008-12-24 04:19:07 +09:00
common_show_footer ();
}
2008-12-24 04:33:23 +09:00
function save_values ( $display , $canonical , $sreg )
{
2008-12-24 04:19:07 +09:00
common_ensure_session ();
$_SESSION [ 'openid_display' ] = $display ;
$_SESSION [ 'openid_canonical' ] = $canonical ;
$_SESSION [ 'openid_sreg' ] = $sreg ;
}
2008-12-24 04:33:23 +09:00
function get_saved_values ()
{
2008-12-24 04:19:07 +09:00
return array ( $_SESSION [ 'openid_display' ],
$_SESSION [ 'openid_canonical' ],
$_SESSION [ 'openid_sreg' ]);
}
2008-12-24 04:33:23 +09:00
function create_new_user ()
{
2008-07-02 22:15:07 +09:00
2008-12-04 03:50:22 +09:00
# FIXME: save invite code before redirect, and check here
2008-12-24 04:19:07 +09:00
if ( common_config ( 'site' , 'closed' ) || common_config ( 'site' , 'inviteonly' )) {
common_user_error ( _ ( 'Registration not allowed.' ));
2008-12-04 03:50:22 +09:00
return ;
}
2008-12-24 04:19:07 +09:00
$nickname = $this -> trimmed ( 'newname' );
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
if ( ! Validate :: string ( $nickname , array ( 'min_length' => 1 ,
'max_length' => 64 ,
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER ))) {
$this -> show_form ( _ ( 'Nickname must have only lowercase letters and numbers and no spaces.' ));
return ;
}
2008-06-23 03:04:37 +09:00
2008-12-24 04:19:07 +09:00
if ( ! User :: allowed_nickname ( $nickname )) {
$this -> show_form ( _ ( 'Nickname not allowed.' ));
return ;
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
if ( User :: staticGet ( 'nickname' , $nickname )) {
$this -> show_form ( _ ( 'Nickname already in use. Try another one.' ));
return ;
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
list ( $display , $canonical , $sreg ) = $this -> get_saved_values ();
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
if ( ! $display || ! $canonical ) {
common_server_error ( _ ( 'Stored OpenID not found.' ));
return ;
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
# Possible race condition... let's be paranoid
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
$other = oid_get_user ( $canonical );
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
if ( $other ) {
common_server_error ( _ ( 'Creating new account for OpenID that already has a user.' ));
return ;
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
if ( $sreg [ 'country' ]) {
if ( $sreg [ 'postcode' ]) {
# XXX: use postcode to get city and region
# XXX: also, store postcode somewhere -- it's valuable!
$location = $sreg [ 'postcode' ] . ', ' . $sreg [ 'country' ];
} else {
$location = $sreg [ 'country' ];
}
}
2008-12-10 10:46:19 +09:00
2008-12-24 04:19:07 +09:00
if ( $sreg [ 'fullname' ] && strlen ( $sreg [ 'fullname' ]) <= 255 ) {
$fullname = $sreg [ 'fullname' ];
}
2008-12-10 10:46:19 +09:00
2008-12-24 04:19:07 +09:00
if ( $sreg [ 'email' ] && Validate :: email ( $sreg [ 'email' ], true )) {
$email = $sreg [ 'email' ];
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
# XXX: add language
# XXX: add timezone
2008-12-10 10:46:19 +09:00
2008-12-24 04:19:07 +09:00
$user = User :: register ( array ( 'nickname' => $nickname ,
'email' => $email ,
'fullname' => $fullname ,
'location' => $location ));
2008-06-18 14:26:38 +09:00
2008-12-24 04:19:07 +09:00
$result = oid_link_user ( $user -> id , $canonical , $display );
2008-12-10 10:46:19 +09:00
2008-12-24 04:19:07 +09:00
oid_set_last ( $display );
common_set_user ( $user );
common_real_login ( true );
2008-12-10 03:03:30 +09:00
if ( isset ( $_SESSION [ 'openid_rememberme' ]) && $_SESSION [ 'openid_rememberme' ]) {
2008-12-24 04:19:07 +09:00
common_rememberme ( $user );
}
2008-12-10 03:03:30 +09:00
unset ( $_SESSION [ 'openid_rememberme' ]);
2008-12-24 04:19:07 +09:00
common_redirect ( common_local_url ( 'showstream' , array ( 'nickname' => $user -> nickname )));
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:33:23 +09:00
function connect_user ()
{
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
$nickname = $this -> trimmed ( 'nickname' );
$password = $this -> trimmed ( 'password' );
2008-06-18 14:26:38 +09:00
2008-12-24 04:19:07 +09:00
if ( ! common_check_user ( $nickname , $password )) {
$this -> show_form ( _ ( 'Invalid username or password.' ));
return ;
}
2008-06-18 14:26:38 +09:00
2008-12-24 04:19:07 +09:00
# They're legit!
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
$user = User :: staticGet ( 'nickname' , $nickname );
2008-06-18 14:26:38 +09:00
2008-12-24 04:19:07 +09:00
list ( $display , $canonical , $sreg ) = $this -> get_saved_values ();
2008-06-18 14:26:38 +09:00
2008-12-24 04:19:07 +09:00
if ( ! $display || ! $canonical ) {
common_server_error ( _ ( 'Stored OpenID not found.' ));
return ;
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
$result = oid_link_user ( $user -> id , $canonical , $display );
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
if ( ! $result ) {
common_server_error ( _ ( 'Error connecting user to OpenID.' ));
return ;
}
2008-07-02 22:15:07 +09:00
2008-12-24 04:19:07 +09:00
oid_update_user ( $user , $sreg );
oid_set_last ( $display );
common_set_user ( $user );
common_real_login ( true );
2008-12-10 03:03:30 +09:00
if ( isset ( $_SESSION [ 'openid_rememberme' ]) && $_SESSION [ 'openid_rememberme' ]) {
2008-12-24 04:19:07 +09:00
common_rememberme ( $user );
}
unset ( $_SESSION [ 'openid_rememberme' ]);
$this -> go_home ( $user -> nickname );
}
2008-12-24 04:33:23 +09:00
function go_home ( $nickname )
{
2008-12-24 04:19:07 +09:00
$url = common_get_returnto ();
if ( $url ) {
# We don't have to return to it again
2008-12-24 04:21:29 +09:00
common_set_returnto ( null );
2008-12-24 04:19:07 +09:00
} else {
$url = common_local_url ( 'all' ,
array ( 'nickname' =>
$nickname ));
}
common_redirect ( $url );
}
2008-12-24 04:33:23 +09:00
function best_new_nickname ( $display , $sreg )
{
2008-12-24 04:19:07 +09:00
# Try the passed-in nickname
if ( $sreg [ 'nickname' ]) {
$nickname = $this -> nicknamize ( $sreg [ 'nickname' ]);
if ( $this -> is_new_nickname ( $nickname )) {
return $nickname ;
}
}
# Try the full name
if ( $sreg [ 'fullname' ]) {
$fullname = $this -> nicknamize ( $sreg [ 'fullname' ]);
if ( $this -> is_new_nickname ( $fullname )) {
return $fullname ;
}
}
# Try the URL
$from_url = $this -> openid_to_nickname ( $display );
if ( $from_url && $this -> is_new_nickname ( $from_url )) {
return $from_url ;
}
# XXX: others?
2008-12-24 04:21:29 +09:00
return null ;
2008-12-24 04:19:07 +09:00
}
2008-12-24 04:33:23 +09:00
function is_new_nickname ( $str )
{
2008-12-24 04:19:07 +09:00
if ( ! Validate :: string ( $str , array ( 'min_length' => 1 ,
'max_length' => 64 ,
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER ))) {
return false ;
}
if ( ! User :: allowed_nickname ( $str )) {
return false ;
}
if ( User :: staticGet ( 'nickname' , $str )) {
return false ;
}
return true ;
}
2008-12-24 04:33:23 +09:00
function openid_to_nickname ( $openid )
{
2008-06-18 14:26:38 +09:00
if ( Auth_Yadis_identifierScheme ( $openid ) == 'XRI' ) {
2008-12-24 04:19:07 +09:00
return $this -> xri_to_nickname ( $openid );
} else {
return $this -> url_to_nickname ( $openid );
}
}
2008-06-18 14:26:38 +09:00
2008-12-24 04:19:07 +09:00
# We try to use an OpenID URL as a legal Laconica user name in this order
# 1. Plain hostname, like http://evanp.myopenid.com/
# 2. One element in path, like http://profile.typekey.com/EvanProdromou/
# or http://getopenid.com/evanprodromou
2008-06-18 14:26:38 +09:00
2008-12-24 04:33:23 +09:00
function url_to_nickname ( $openid )
{
2008-12-24 04:19:07 +09:00
static $bad = array ( 'query' , 'user' , 'password' , 'port' , 'fragment' );
$parts = parse_url ( $openid );
# If any of these parts exist, this won't work
foreach ( $bad as $badpart ) {
if ( array_key_exists ( $badpart , $parts )) {
2008-12-24 04:21:29 +09:00
return null ;
2008-12-24 04:19:07 +09:00
}
}
# We just have host and/or path
# If it's just a host...
if ( array_key_exists ( 'host' , $parts ) &&
( ! array_key_exists ( 'path' , $parts ) || strcmp ( $parts [ 'path' ], '/' ) == 0 ))
{
$hostparts = explode ( '.' , $parts [ 'host' ]);
# Try to catch common idiom of nickname.service.tld
if (( count ( $hostparts ) > 2 ) &&
( strlen ( $hostparts [ count ( $hostparts ) - 2 ]) > 3 ) && # try to skip .co.uk, .com.au
( strcmp ( $hostparts [ 0 ], 'www' ) != 0 ))
{
return $this -> nicknamize ( $hostparts [ 0 ]);
} else {
# Do the whole hostname
return $this -> nicknamize ( $parts [ 'host' ]);
}
} else {
if ( array_key_exists ( 'path' , $parts )) {
# Strip starting, ending slashes
$path = preg_replace ( '@/$@' , '' , $parts [ 'path' ]);
$path = preg_replace ( '@^/@' , '' , $path );
if ( strpos ( $path , '/' ) === false ) {
return $this -> nicknamize ( $path );
}
}
}
2008-12-24 04:21:29 +09:00
return null ;
2008-12-24 04:19:07 +09:00
}
2008-12-24 04:33:23 +09:00
function xri_to_nickname ( $xri )
{
2008-12-24 04:19:07 +09:00
$base = $this -> xri_base ( $xri );
if ( ! $base ) {
2008-12-24 04:21:29 +09:00
return null ;
2008-12-24 04:19:07 +09:00
} else {
# =evan.prodromou
# or @gratis*evan.prodromou
$parts = explode ( '*' , substr ( $base , 1 ));
return $this -> nicknamize ( array_pop ( $parts ));
}
}
2008-12-24 04:33:23 +09:00
function xri_base ( $xri )
{
2008-12-24 04:19:07 +09:00
if ( substr ( $xri , 0 , 6 ) == 'xri://' ) {
return substr ( $xri , 6 );
} else {
return $xri ;
}
}
# Given a string, try to make it work as a nickname
2008-12-24 04:33:23 +09:00
function nicknamize ( $str )
{
2008-12-24 04:19:07 +09:00
$str = preg_replace ( '/\W/' , '' , $str );
return strtolower ( $str );
}
2008-06-18 14:26:38 +09:00
}