mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 00:52:33 -04:00
582 lines
17 KiB
PHP
582 lines
17 KiB
PHP
<?php
|
|
|
|
namespace Zotlabs\Module;
|
|
|
|
use App;
|
|
use Zotlabs\Lib\Config;
|
|
use Zotlabs\Web\Controller;
|
|
|
|
require_once('include/security.php');
|
|
require_once('include/channel.php');
|
|
|
|
|
|
class Register extends Controller {
|
|
|
|
const MYP = 'ZAR'; // ZAR0x
|
|
const VERSION = '2.0.0';
|
|
|
|
function init() {
|
|
|
|
// ZAR0
|
|
|
|
$result = null;
|
|
$cmd = ((argc() > 1) ? argv(1) : '');
|
|
|
|
// Provide a stored request for somebody desiring a connection
|
|
// when they first need to register someplace. Once they've
|
|
// created a channel, we'll try to revive the connection request
|
|
// and process it.
|
|
|
|
if(isset($_REQUEST['connect']))
|
|
$_SESSION['connect'] = $_REQUEST['connect'];
|
|
|
|
switch($cmd) {
|
|
case 'invite_check.json':
|
|
$result = check_account_invite($_REQUEST['invite_code']);
|
|
break;
|
|
case 'email_check.json':
|
|
$result = check_account_email($_REQUEST['email']);
|
|
break;
|
|
case 'password_check.json':
|
|
$result = check_account_password($_REQUEST['password1']);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if($result) {
|
|
json_return_and_die($result);
|
|
}
|
|
}
|
|
|
|
function post() {
|
|
|
|
check_form_security_token_redirectOnErr('/register', 'register');
|
|
|
|
/**
|
|
* [hilmar:]
|
|
* It may happen, the posted form arrives in a strange fashion. With the control of the duty hours
|
|
* for registration, the input form was disabled at html. While receiving posted data, checks are
|
|
* required if all is on the right road (most posts are not accepted during off duty).
|
|
*
|
|
*/
|
|
|
|
|
|
$act = q("SELECT COUNT(*) AS act FROM account")[0]['act'];
|
|
$is247 = false;
|
|
$ip = $_SERVER['REMOTE_ADDR'];
|
|
$sameip = intval(Config::Get('system','register_sameip', 3));
|
|
$arr = $_POST;
|
|
$invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
|
|
$name = '';
|
|
$nick = '';
|
|
$email = ((x($arr,'email')) ? notags(punify(trim($arr['email']))) : '');
|
|
$password = ((x($arr,'password')) ? trim($arr['password']) : '');
|
|
$password2 = ((x($arr,'password2')) ? trim($arr['password2']) : '');
|
|
$register_msg = ((x($arr,'register_msg')) ? notags(trim($arr['register_msg'])) : '');
|
|
$reonar = [];
|
|
$auto_create = Config::Get('system','auto_channel_create', 1);
|
|
$duty = zar_register_dutystate();
|
|
|
|
if (!Config::Get('system', 'register_duty_jso')) {
|
|
// if not yet configured default to true
|
|
$duty = array( 'isduty' => true, 'atfrm' => '', 'nowfmt' => '');
|
|
}
|
|
|
|
if($auto_create) {
|
|
$name = escape_tags(trim($arr['name']));
|
|
|
|
$name_error = validate_channelname($name);
|
|
if($name_error) {
|
|
notice($name_error . EOL);
|
|
return;
|
|
}
|
|
|
|
$nick = mb_strtolower(escape_tags(trim($arr['nickname'])));
|
|
if(!$nick) {
|
|
notice(t('Nickname is required.'));
|
|
return;
|
|
}
|
|
|
|
if($nick === 'sys') {
|
|
notice(t('Reserved nickname. Please choose another.') . EOL);
|
|
return;
|
|
}
|
|
|
|
if(check_webbie([$nick]) !== $nick) {
|
|
notice(t('Nickname has unsupported characters or is already being used on this site.') . EOL);
|
|
return;
|
|
}
|
|
}
|
|
|
|
$email_verify = Config::Get('system', 'verify_email');
|
|
if ($email_verify && !$email) {
|
|
notice(t('Email address required') . EOL);
|
|
return;
|
|
}
|
|
|
|
if ($email) {
|
|
$email_result = check_account_email($email);
|
|
if ($email_result['error']) {
|
|
if ($email_result['email_unverified']) {
|
|
goaway(z_root() . '/regate/' . bin2hex($email) . 'e');
|
|
}
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// case when an invited prepares the own account by supply own pw, accept tos, prepage channel (if auto)
|
|
if ($email && $invite_code) {
|
|
if ( preg_match('/^[a-z0-9]{12,12}$/', $invite_code ) ) {
|
|
$is247 = true;
|
|
}
|
|
}
|
|
|
|
if ($act > 0 && !$is247 && !$duty['isduty']) {
|
|
// normally (except very 1st timr after install), that should never arrive here (ie js hack or sth like)
|
|
// log suitable for f2b also
|
|
$logmsg = 'Unexpected registration request off duty';
|
|
notice($logmsg);
|
|
zar_log('ZAR0230S ' . $logmsg);
|
|
return;
|
|
}
|
|
|
|
if ($sameip) {
|
|
$f = q("SELECT COUNT(reg_atip) AS atip FROM register WHERE reg_vital = 1 AND reg_atip = '%s' ",
|
|
dbesc($ip)
|
|
);
|
|
if ($f && $f[0]['atip'] >= $sameip) {
|
|
$logmsg = 'ZAR0239S Exceeding same ip register request of ' . $sameip;
|
|
notice('Registrations from same IP exceeded.');
|
|
zar_log($logmsg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!$password) {
|
|
notice(t('No password provided') . EOL);
|
|
return;
|
|
}
|
|
|
|
if ($password !== $password2) {
|
|
notice(t('Passwords do not match') . EOL);
|
|
return;
|
|
}
|
|
|
|
$password_result = check_account_password($password);
|
|
if(!empty($password_result['error'])) {
|
|
$msg = $password_result['message'];
|
|
notice($msg);
|
|
zar_log($msg);
|
|
return;
|
|
}
|
|
|
|
$salt = random_string(32);
|
|
$password = $salt . ',' . hash('whirlpool', $salt . $password);
|
|
|
|
// accept tos
|
|
if(! x($_POST,'tos')) {
|
|
// msg!
|
|
notice(t('Terms of Service not accepted') . EOL);
|
|
return;
|
|
}
|
|
|
|
$policy = Config::Get('system','register_policy');
|
|
$invonly = Config::Get('system','invitation_only');
|
|
$invalso = Config::Get('system','invitation_also');
|
|
|
|
switch($policy) {
|
|
|
|
case REGISTER_OPEN:
|
|
$flags = ACCOUNT_OK;
|
|
break;
|
|
|
|
case REGISTER_APPROVE:
|
|
$flags = ACCOUNT_PENDING;
|
|
break;
|
|
|
|
default:
|
|
case REGISTER_CLOSED:
|
|
if(! is_site_admin()) {
|
|
notice( t('Permission denied.') . EOL );
|
|
return;
|
|
}
|
|
$flags = ACCOUNT_BLOCKED;
|
|
break;
|
|
}
|
|
|
|
if($email_verify && ($policy == REGISTER_OPEN || $policy == REGISTER_APPROVE))
|
|
$flags = ($flags | ACCOUNT_UNVERIFIED);
|
|
|
|
// $arr has $_POST;
|
|
$arr['account_flags'] = $flags;
|
|
$now = datetime_convert();
|
|
$well = false;
|
|
|
|
// s3
|
|
if ($invite_code) {
|
|
|
|
if ($invonly || $invalso) {
|
|
|
|
$reg = q("SELECT * from register WHERE reg_vital = 1 AND reg_didx = 'i' AND reg_hash = '%s'",
|
|
dbesc($invite_code)
|
|
);
|
|
|
|
if ($reg && count($reg) == 1) {
|
|
$reg = $reg[0];
|
|
if ($reg['reg_email'] == ($email)) {
|
|
|
|
if ($reg['reg_startup'] <= $now && $reg['reg_expires'] >= $now) {
|
|
|
|
if ($auto_create) {
|
|
$reonar['chan.name'] = $name;
|
|
$reonar['chan.did1'] = $nick;
|
|
}
|
|
|
|
q("UPDATE register set reg_pass = '%s', reg_stuff = '%s' WHERE reg_id = '%s'",
|
|
dbesc($password),
|
|
dbesc(json_encode($reonar)),
|
|
intval($reg['reg_id'])
|
|
);
|
|
|
|
$msg = t('Invitation code succesfully applied');
|
|
zar_log('ZAR0237I ' . $msg . ', ' . $email);
|
|
// msg!
|
|
info($msg . EOL);
|
|
|
|
|
|
// the invitecode has verified us and we have all the info we need
|
|
// take the shortcut.
|
|
|
|
$_SESSION['zar']['invite_in_progress'] = true;
|
|
|
|
$mod = new Regate();
|
|
$_REQUEST['form_security_token'] = get_form_security_token("regate");
|
|
App::$argc = 2;
|
|
App::$argv[0] = 'regate';
|
|
App::$argv[1] = bin2hex($reg['reg_did2']) . 'i';
|
|
return $mod->post();
|
|
|
|
} else {
|
|
// msg!
|
|
notice(t('Invitation not in time or too late') . EOL);
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
// no match email adr
|
|
$msg = t('Invitation email failed');
|
|
zar_log('ZAR0235S ' . $msg);
|
|
notice($msg . EOL);
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
// no match invitecode
|
|
$msg = t('Invitation code failed') ;
|
|
zar_log('ZAR0234S ' . $msg);
|
|
notice( $msg . EOL);
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
notice(t('Invitations are not available') . EOL);
|
|
return;
|
|
}
|
|
|
|
}
|
|
else {
|
|
if (!$invonly) {
|
|
$well = true;
|
|
}
|
|
else {
|
|
$msg = t('Registration on this hub is by invitation only') . EOL;
|
|
notice($msg);
|
|
zar_log('ZAR0233E ' . $msg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// check max daily registrations after we have dealt with the invitecode
|
|
if (self::check_reg_limits()['is']) {
|
|
notice('Max registrations per day exceeded.');
|
|
return;
|
|
}
|
|
|
|
if ($well) {
|
|
|
|
if($policy == REGISTER_OPEN || $policy == REGISTER_APPROVE ) {
|
|
|
|
$cfgdelay = Config::Get('system', 'register_delay', '0i');
|
|
$reg_delayed = calculate_adue( $cfgdelay );
|
|
$regdelay = (($reg_delayed) ? datetime_convert(date_default_timezone_get(), 'UTC', $reg_delayed['due']) : $now);
|
|
|
|
$cfgexpire = Config::Get('system', 'register_expire', '3d');
|
|
$reg_expires = calculate_adue( $cfgexpire );
|
|
$regexpire = (($reg_expires) ? datetime_convert(date_default_timezone_get(), 'UTC', $reg_expires['due']) : datetime_convert('UTC', 'UTC', 'now + 99 years'));
|
|
|
|
// handle an email request that will be verified or an ivitation associated with an email address
|
|
if ($email > '' && $email_verify) {
|
|
// enforce in case of icdone
|
|
$flags |= ACCOUNT_UNVERIFIED;
|
|
$empin = $pass2 = random_string(24);
|
|
$did2 = $email;
|
|
$didx = 'e';
|
|
|
|
$reonar['from'] = Config::Get('system', 'from_email');
|
|
$reonar['to'] = $email;
|
|
$reonar['subject'] = sprintf( t('Registration confirmation for %s'), Config::Get('system','sitename'));
|
|
$reonar['txttemplate']= replace_macros(get_intltext_template('register_verify_member.tpl'),
|
|
[
|
|
'$sitename' => Config::Get('system','sitename'),
|
|
'$siteurl' => z_root(),
|
|
'$email' => $email,
|
|
'$timeframe' => [$regdelay, $regexpire],
|
|
'$mail' => bin2hex($email) . 'e',
|
|
'$ko' => bin2hex(substr($empin,0,4)),
|
|
'$hash' => $empin
|
|
]
|
|
);
|
|
zar_reg_mail($reonar);
|
|
|
|
} else {
|
|
// that is an anonymous request without email or with email not to verify
|
|
$acpin = $pass2 = rand(100000,999999);
|
|
$did2 = rand(10,99);
|
|
$didx = 'a';
|
|
// enforce delayed verify
|
|
$flags = ($flags | ACCOUNT_UNVERIFIED);
|
|
if ($email) {
|
|
$reonar['email.untrust'] = $email;
|
|
$reonar['email.comment'] = 'received, but no need for';
|
|
}
|
|
}
|
|
|
|
if ($auto_create) {
|
|
$reonar['chan.name'] = $name;
|
|
$reonar['chan.did1'] = $nick;
|
|
}
|
|
|
|
if ($policy == REGISTER_APPROVE) {
|
|
$reonar['msg'] = $register_msg;
|
|
}
|
|
|
|
$reg = q("INSERT INTO register ("
|
|
. "reg_flags,reg_didx,reg_did2,reg_hash,reg_created,reg_startup,reg_expires,"
|
|
. "reg_email,reg_pass,reg_lang,reg_atip,reg_stuff)"
|
|
. " VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
|
|
intval($flags),
|
|
dbesc($didx),
|
|
dbesc($did2),
|
|
dbesc($pass2),
|
|
dbesc($now),
|
|
dbesc($regdelay),
|
|
dbesc($regexpire),
|
|
dbesc($email),
|
|
dbesc($password),
|
|
dbesc(App::$language),
|
|
dbesc($ip),
|
|
dbesc(json_encode($reonar))
|
|
);
|
|
|
|
if ($didx == 'a') {
|
|
|
|
$lid = q("SELECT reg_id FROM register WHERE reg_vital = 1 AND reg_did2 = '%s' AND reg_pass = '%s' ",
|
|
dbesc($did2),
|
|
dbesc($password)
|
|
);
|
|
|
|
if ($lid && count($lid) == 1 ) {
|
|
|
|
$didnew = ( $lid[0]['reg_id'] . $did2 )
|
|
. ( substr( base_convert( md5( $lid[0]['reg_id'] . $did2 ), 16, 10 ),-2 ) );
|
|
|
|
$reg = q("UPDATE register SET reg_did2 = CONCAT('d','%s') WHERE reg_id = %d ",
|
|
dbesc($didnew), intval($lid[0]['reg_id'])
|
|
);
|
|
|
|
zar_log( 'ZAR0239A ' . t('New register request') . ' d' . $didnew . ', '
|
|
. $regdelay . ' - ' . $regexpire);
|
|
|
|
if($reg_delayed) {
|
|
// this could be removed to make registration harder
|
|
$_SESSION['zar']['id'] = 'd' . $didnew;
|
|
$_SESSION['zar']['pin'] = $pass2;
|
|
$_SESSION['zar']['delayed'] = true;
|
|
$_SESSION['zar']['regdelay'] = datetime_convert('UTC', 'UTC', $regdelay, 'c');
|
|
$_SESSION['zar']['regexpire'] = datetime_convert('UTC', 'UTC', $regexpire, 'c');
|
|
}
|
|
else {
|
|
$_SESSION['zar']['pin'] = $pass2;
|
|
}
|
|
|
|
goaway(z_root() . '/regate/' . bin2hex('d' . $didnew) . 'a' );
|
|
}
|
|
else {
|
|
$msg = t('Error creating dId A');
|
|
notice( $msg );
|
|
zar_log( 'ZAR0239D,' . $msg . ' ' . $did2);
|
|
}
|
|
}
|
|
goaway(z_root() . '/regate/' . bin2hex($email) . $didx );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function get() {
|
|
|
|
$registration_is = '';
|
|
$register_msg = '';
|
|
$other_sites = '';
|
|
|
|
if(intval(Config::Get('system','register_policy')) === REGISTER_CLOSED) {
|
|
if(intval(Config::Get('system','directory_mode')) === DIRECTORY_MODE_STANDALONE) {
|
|
notice(t('Registration on this hub is disabled.') . EOL);
|
|
return;
|
|
}
|
|
|
|
$mod = new Pubsites();
|
|
return $mod->get();
|
|
}
|
|
|
|
if(intval(Config::Get('system','register_policy')) == REGISTER_APPROVE) {
|
|
$register_msg = ['register_msg', t('Why do you want to join this hub?'), ((x($_REQUEST,'register_msg')) ? $_REQUEST['register_msg'] : ''), t('This will help to review your registration')];
|
|
$registration_is = t('Registration on this hub is by approval only.');
|
|
$other_sites = '<a href="pubsites">' . t('Register at another affiliated hub if preferred') . '</a>';
|
|
}
|
|
|
|
$duty = zar_register_dutystate();
|
|
|
|
if (!Config::Get('system', 'register_duty_jso')) {
|
|
// if not yet configured default to true
|
|
$duty = array( 'isduty' => true, 'atfrm' => '', 'nowfmt' => '');
|
|
}
|
|
|
|
$invitations = false;
|
|
if(intval(Config::Get('system','invitation_only'))) {
|
|
$invitations = true;
|
|
$registration_is = t('Registration on this hub is by invitation only.');
|
|
$other_sites = '<a href="pubsites">' . t('Register at another affiliated hub') . '</a>';
|
|
} elseif (intval(Config::Get('system','invitation_also'))) {
|
|
$invitations = true;
|
|
}
|
|
|
|
$opal = self::check_reg_limits();
|
|
if ( $opal['is'])
|
|
$duty['atform'] = 'disabled';
|
|
|
|
// Configurable terms of service link
|
|
$tosurl = Config::Get('system','tos_url');
|
|
if(! $tosurl)
|
|
$tosurl = z_root() . '/help/TermsOfService';
|
|
|
|
$toslink = '<a href="' . $tosurl . '" target="_blank">' . t('Terms of Service') . '</a>';
|
|
|
|
// Configurable whether to restrict age or not - default is based on international legal requirements
|
|
// This can be relaxed if you are on a restricted server that does not share with public servers
|
|
|
|
if(Config::Get('system','no_age_restriction')) {
|
|
$label_tos = sprintf( t('I accept the %s for this website'), $toslink);
|
|
}
|
|
else {
|
|
$age = Config::Get('system','minimum_age');
|
|
if(!$age) {
|
|
$age = 13;
|
|
}
|
|
$label_tos = sprintf( t('I am over %s years of age and accept the %s for this website'), $age, $toslink);
|
|
}
|
|
|
|
$enable_tos = 1 - intval(Config::Get('system','no_termsofservice'));
|
|
|
|
$auto_create = Config::Get('system', 'auto_channel_create', 1);
|
|
$email_verify = Config::Get('system','verify_email');
|
|
|
|
$emailval = ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : "");
|
|
$email = ['email',
|
|
t('Your email address'),
|
|
$emailval,
|
|
(($email_verify) ? t('Required') : t('Optional')),
|
|
(($email_verify) ? '*' : ''),
|
|
$duty['atform']
|
|
];
|
|
|
|
$password = array('password', t('Choose a password'), '', '', '', $duty['atform']);
|
|
$password2 = array('password2', t('Please re-enter your password'), '', '', '', $duty['atform']);
|
|
|
|
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
|
|
|
|
$name = array('name', t('Your name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real name is preferred'), '', '', $duty['atform']);
|
|
$nickhub = '@' . str_replace(array('http://','https://','/'), '', Config::Get('system','baseurl'));
|
|
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), t('Your nickname will be used to create an easy to remember channel address'), '', '', $duty['atform']);
|
|
|
|
$tos = array('tos', $label_tos, ((x($_REQUEST,'tos')) ? $_REQUEST['tos'] : ''), '', [t('No'),t('Yes')], $duty['atform']);
|
|
|
|
require_once('include/bbcode.php');
|
|
|
|
$o = replace_macros(get_markup_template('register.tpl'), array(
|
|
'$form_security_token' => get_form_security_token("register"),
|
|
'$title' => t('Registration'),
|
|
'$reg_is' => $registration_is,
|
|
'$register_msg' => $register_msg,
|
|
'$registertext' => bbcode(Config::Get('system','register_text')),
|
|
'$other_sites' => $other_sites,
|
|
'$msg' => $opal['msg'],
|
|
'$invitations' => $invitations,
|
|
'$invite_code' => $invite_code,
|
|
'$haveivc' => t('I have an invite code'),
|
|
'$now' => $duty['nowfmt'],
|
|
'$atform' => $duty['atform'],
|
|
'$auto_create' => $auto_create,
|
|
'$name' => $name,
|
|
'$nickname' => $nickname,
|
|
'$enable_tos' => $enable_tos,
|
|
'$tos' => $tos,
|
|
'$email' => $email,
|
|
'$validate' => $validate,
|
|
'$validate_link'=> $validate_link,
|
|
'$validate_here'=> $validate_here,
|
|
'$pass1' => $password,
|
|
'$pass2' => $password2,
|
|
'$submit' => t('Register'),
|
|
'$nickhub' => $nickhub
|
|
|
|
));
|
|
|
|
return $o;
|
|
}
|
|
|
|
function check_reg_limits() {
|
|
// check against register, account
|
|
$rear = array( 'is' => false, 'rn' => 0, 'an' => 0, 'msg' => '' );
|
|
|
|
$max_dailies = intval(Config::Get('system', 'max_daily_registrations', 50));
|
|
|
|
if ($max_dailies) {
|
|
|
|
$r = q("SELECT COUNT(reg_id) AS nr FROM register WHERE reg_vital = 1 AND reg_created > %s - INTERVAL %s",
|
|
db_utcnow(), db_quoteinterval('1 day')
|
|
);
|
|
|
|
$rear['is'] = ( $r && $r[0]['nr'] >= $max_dailies ) ? true : false;
|
|
$rear['rn'] = $r[0]['nr'];
|
|
|
|
if (!$rear['is']) {
|
|
$r = q("SELECT COUNT(account_id) AS nr FROM account WHERE account_created > %s - INTERVAL %s",
|
|
db_utcnow(), db_quoteinterval('1 day')
|
|
);
|
|
|
|
$rear['is'] = ( $r && ($r[0]['nr'] + $rear['rn']) >= $max_dailies ) ? true : false;
|
|
$rear['ra'] = $r[0]['nr'];
|
|
}
|
|
|
|
if ( $rear['is']) {
|
|
$rear['msg'] = t('This site has exceeded the number of allowed daily account registrations.');
|
|
zar_log('ZAR0333W ' . $rear['msg']);
|
|
$rear['is'] = true;
|
|
}
|
|
}
|
|
return $rear;
|
|
}
|
|
}
|