diff options
Diffstat (limited to 'mod/id.php')
-rw-r--r-- | mod/id.php | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/mod/id.php b/mod/id.php new file mode 100644 index 000000000..bd4c1fa89 --- /dev/null +++ b/mod/id.php @@ -0,0 +1,310 @@ +<?php +/** + * @file mod/id.php + * @brief OpenID implementation + */ + +require 'library/openid/provider/provider.php'; + + +$attrMap = array( + 'namePerson/first' => t('First Name'), + 'namePerson/last' => t('Last Name'), + 'namePerson/friendly' => t('Nickname'), + 'namePerson' => t('Full Name'), + 'contact/internet/email' => t('Email'), + 'contact/email' => t('Email'), + 'media/image/aspect11' => t('Profile Photo'), + 'media/image' => t('Profile Photo'), + 'media/image/default' => t('Profile Photo'), + 'media/image/16x16' => t('Profile Photo 16px'), + 'media/image/32x32' => t('Profile Photo 32px'), + 'media/image/48x48' => t('Profile Photo 48px'), + 'media/image/64x64' => t('Profile Photo 64px'), + 'media/image/80x80' => t('Profile Photo 80px'), + 'media/image/128x128' => t('Profile Photo 128px'), + 'timezone' => t('Timezone'), + 'contact/web/default' => t('Homepage URL'), + 'language/pref' => t('Language'), + 'birthDate/birthYear' => t('Birth Year'), + 'birthDate/birthMonth' => t('Birth Month'), + 'birthDate/birthday' => t('Birth Day'), + 'birthDate' => t('Birthdate'), + 'gender' => t('Gender'), +); + + +/** + * @brief Entrypoint for the OpenID implementation. + * + * @param App &$a + */ +function id_init(&$a) { + + logger('id: ' . print_r($_REQUEST, true)); + + if(argc() > 1) { + $which = argv(1); + } else { + $a->error = 404; + return; + } + + $profile = ''; + $channel = $a->get_channel(); + profile_load($a,$which,$profile); + + $op = new MysqlProvider; + $op->server(); +} + +/** + * @brief Returns user data needed for OpenID. + * + * If no $handle is provided we will use local_channel() by default. + * + * @param string $handle (default null) + * @return boolean|array + */ +function getUserData($handle = null) { + if (! local_channel()) { + notice( t('Permission denied.') . EOL); + get_app()->page['content'] = login(); + + return false; + } + +// logger('handle: ' . $handle); + + if ($handle) { + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1", + dbesc($handle) + ); + } else { + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d", + intval(local_channel()) + ); + } + + if (! r) + return false; + + $x = q("select * from account where account_id = %d limit 1", + intval($r[0]['channel_account_id']) + ); + if ($x) + $r[0]['email'] = $x[0]['account_email']; + + $p = q("select * from profile where is_default = 1 and uid = %d limit 1", + intval($r[0]['channel_account_id']) + ); + + $gender = ''; + if ($p[0]['gender'] == t('Male')) + $gender = 'M'; + if ($p[0]['gender'] == t('Female')) + $gender = 'F'; + + $r[0]['firstName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],0,strpos($r[0]['channel_name'],' ')) : $r[0]['channel_name']); + $r[0]['lastName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],strpos($r[0]['channel_name'],' ')+1) : ''); + $r[0]['namePerson'] = $r[0]['channel_name']; + $r[0]['pphoto'] = $r[0]['xchan_photo_l']; + $r[0]['pphoto16'] = z_root() . '/photo/profile/16/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto32'] = z_root() . '/photo/profile/32/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto48'] = z_root() . '/photo/profile/48/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto64'] = z_root() . '/photo/profile/64/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto80'] = z_root() . '/photo/profile/80/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto128'] = z_root() . '/photo/profile/128/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['timezone'] = $r[0]['channel_timezone']; + $r[0]['url'] = $r[0]['xchan_url']; + $r[0]['language'] = (($x[0]['account_language']) ? $x[0]['account_language'] : 'en'); + $r[0]['birthyear'] = ((intval(substr($p[0]['dob'],0,4))) ? intval(substr($p[0]['dob'],0,4)) : ''); + $r[0]['birthmonth'] = ((intval(substr($p[0]['dob'],5,2))) ? intval(substr($p[0]['dob'],5,2)) : ''); + $r[0]['birthday'] = ((intval(substr($p[0]['dob'],8,2))) ? intval(substr($p[0]['dob'],8,2)) : ''); + $r[0]['birthdate'] = (($r[0]['birthyear'] && $r[0]['birthmonth'] && $r[0]['birthday']) ? $p[0]['dob'] : ''); + $r[0]['gender'] = $gender; + + return $r[0]; + +/* +* if(isset($_POST['login'],$_POST['password'])) { +* $login = mysql_real_escape_string($_POST['login']); +* $password = sha1($_POST['password']); +* $q = mysql_query("SELECT * FROM Users WHERE login = '$login' AND password = '$password'"); +* if($data = mysql_fetch_assoc($q)) { +* return $data; +* } +* if($handle) { +* echo 'Wrong login/password.'; +* } +* } +* if($handle) { +* ?> +* <form action="" method="post"> +* <input type="hidden" name="openid.assoc_handle" value="<?php echo $handle?>"> +* Login: <input type="text" name="login"><br> +* Password: <input type="password" name="password"><br> +* <button>Submit</button> +* </form> +* <?php +* die(); +* } +*/ + +} + + +/** + * @brief MySQL provider for OpenID implementation. + * + */ +class MysqlProvider extends LightOpenIDProvider { + + // See http://openid.net/specs/openid-attribute-properties-list-1_0-01.html + // This list contains a few variations of these attributes to maintain + // compatibility with legacy clients + + private $attrFieldMap = array( + 'namePerson/first' => 'firstName', + 'namePerson/last' => 'lastName', + 'namePerson/friendly' => 'channel_address', + 'namePerson' => 'namePerson', + 'contact/internet/email' => 'email', + 'contact/email' => 'email', + 'media/image/aspect11' => 'pphoto', + 'media/image' => 'pphoto', + 'media/image/default' => 'pphoto', + 'media/image/16x16' => 'pphoto16', + 'media/image/32x32' => 'pphoto32', + 'media/image/48x48' => 'pphoto48', + 'media/image/64x64' => 'pphoto64', + 'media/image/80x80' => 'pphoto80', + 'media/image/128x128' => 'pphoto128', + 'timezone' => 'timezone', + 'contact/web/default' => 'url', + 'language/pref' => 'language', + 'birthDate/birthYear' => 'birthyear', + 'birthDate/birthMonth' => 'birthmonth', + 'birthDate/birthday' => 'birthday', + 'birthDate' => 'birthdate', + 'gender' => 'gender', + ); + + function setup($identity, $realm, $assoc_handle, $attributes) { + global $attrMap; + +// logger('identity: ' . $identity); +// logger('realm: ' . $realm); +// logger('assoc_handle: ' . $assoc_handle); +// logger('attributes: ' . print_r($attributes,true)); + + $data = getUserData($assoc_handle); + + +/** @FIXME this needs to be a template with localised strings */ + + $o .= '<form action="" method="post">' + . '<input type="hidden" name="openid.assoc_handle" value="' . $assoc_handle . '">' + . '<input type="hidden" name="login" value="' . $_POST['login'] .'">' + . '<input type="hidden" name="password" value="' . $_POST['password'] .'">' + . "<b>$realm</b> wishes to authenticate you."; + if($attributes['required'] || $attributes['optional']) { + $o .= " It also requests following information (required fields marked with *):" + . '<ul>'; + + foreach($attributes['required'] as $attr) { + if(isset($this->attrMap[$attr])) { + $o .= '<li>' + . '<input type="checkbox" name="attributes[' . $attr . ']"> ' + . $this->attrMap[$attr] . ' <span class="required">*</span></li>'; + } + } + + foreach($attributes['optional'] as $attr) { + if(isset($this->attrMap[$attr])) { + $o .= '<li>' + . '<input type="checkbox" name="attributes[' . $attr . ']"> ' + . $this->attrMap[$attr] . '</li>'; + } + } + $o .= '</ul>'; + } + $o .= '<br>' + . '<button name="once">Allow once</button> ' + . '<button name="always">Always allow</button> ' + . '<button name="cancel">cancel</button> ' + . '</form>'; + + get_app()->page['content'] .= $o; + } + + function checkid($realm, &$attributes) { + + logger('checkid: ' . $realm); + logger('checkid attrs: ' . print_r($attributes,true)); + + if(isset($_POST['cancel'])) { + $this->cancel(); + } + + $data = getUserData(); + if(! $data) { + return false; + } + + $q = get_pconfig(local_channel(), 'openid', $realm); + + $attrs = array(); + if($q) { + $attrs = $q; + } elseif(isset($_POST['attributes'])) { + $attrs = array_keys($_POST['attributes']); + } elseif(!isset($_POST['once']) && !isset($_POST['always'])) { + return false; + } + + $attributes = array(); + foreach($attrs as $attr) { + if(isset($this->attrFieldMap[$attr])) { + $attributes[$attr] = $data[$this->attrFieldMap[$attr]]; + } + } + + if(isset($_POST['always'])) { + set_pconfig(local_channel(),'openid',$realm,array_keys($attributes)); + } + + return z_root() . '/id/' . $data['channel_address']; + } + + function assoc_handle() { + logger('assoc_handle'); + $channel = get_app()->get_channel(); + + return z_root() . '/channel/' . $channel['channel_address']; + } + + function setAssoc($handle, $data) { + logger('setAssoc'); + $channel = channelx_by_nick(basename($handle)); + if($channel) + set_pconfig($channel['channel_id'],'openid','associate',$data); + } + + function getAssoc($handle) { + logger('getAssoc: ' . $handle); + + $channel = channelx_by_nick(basename($handle)); + if($channel) + return get_pconfig($channel['channel_id'], 'openid', 'associate'); + + return false; + } + + function delAssoc($handle) { + logger('delAssoc'); + $channel = channelx_by_nick(basename($handle)); + if($channel) + return del_pconfig($channel['channel_id'], 'openid', 'associate'); + } +} |