aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/account.php585
-rw-r--r--include/bbcode.php21
-rw-r--r--include/datetime.php36
-rw-r--r--include/features.php73
-rw-r--r--include/js_strings.php7
-rw-r--r--include/security.php106
-rw-r--r--include/text.php31
7 files changed, 741 insertions, 118 deletions
diff --git a/include/account.php b/include/account.php
index fefe61d15..991e799b5 100644
--- a/include/account.php
+++ b/include/account.php
@@ -35,7 +35,7 @@ function check_account_email($email) {
return $result;
if(! validate_email($email))
- $result['message'] .= t('Not a valid email address') . EOL;
+ $result['message'] .= t('Email address not valid') . EOL;
elseif(! allowed_email($email))
$result['message'] = t('Your email domain is not among those allowed on this site');
else {
@@ -71,17 +71,30 @@ function check_account_password($password) {
function check_account_invite($invite_code) {
$result = array('error' => false, 'message' => '');
- $using_invites = get_config('system','invitation_only');
+ // [hilmar ->
+ $using_invites = (get_config('system','invitation_only')
+ || get_config('system','invitation_also'));
if($using_invites) {
+
if(! $invite_code) {
- $result['message'] .= t('An invitation is required.') . EOL;
- }
- $r = q("select * from register where hash = '%s' limit 1", dbesc($invite_code));
- if(! $r) {
- $result['message'] .= t('Invitation could not be verified.') . EOL;
+
+ $result['message']
+ .= 'ZAR0510E,' . t('An invitation is required.') . EOL;
+
+ } else {
+
+ // check if invite code exists
+ $r = q("SELECT * FROM register WHERE reg_hash = '%s' AND reg_vital = 1 LIMIT 1",
+ dbesc($invite_code));
+ if(! $r) {
+ $result['message']
+ .= 'ZAR0511E,' . t('Invitation could not be verified.') . EOL;
+ }
}
}
+ // <- hilmar]
+
if(strlen($result['message']))
$result['error'] = true;
@@ -107,8 +120,8 @@ function account_total() {
return false;
}
-
-function account_store_lowlevel($arr) {
+// legacy
+function account_store_lowlevel_IS_OBSOLETE($arr) {
$store = [
'account_parent' => ((array_key_exists('account_parent',$arr)) ? $arr['account_parent'] : '0'),
@@ -130,12 +143,21 @@ function account_store_lowlevel($arr) {
'account_password_changed' => ((array_key_exists('account_password_changed',$arr)) ? $arr['account_password_changed'] : '0001-01-01 00:00:00')
];
+ // never ever is this a create table but a pdo insert into account
+ // strange function placement in text.php (obscure by design :-)
return create_table_from_array('account',$store);
-
+ // the TODO may be to adjust others using create_table_from_array():
+ // channel.php
+ // connections.php
+ // event.php
+ // hubloc.php
+ // import.php
}
-function create_account($arr) {
+
+// legacy
+function create_account_IS_OBSOLETE($arr) {
// Required: { email, password }
@@ -259,10 +281,161 @@ function create_account($arr) {
return $result;
}
+/**
+ * create_account_from_register
+ * @author hilmar runge
+ * @since 2020-02-20
+ *
+ * Account creation only happens via table register.
+ * This function creates the account when all conditions are solved.
+ *
+ */
+function create_account_from_register($arr) {
+
+ $result = array('success' => false, 'message' => 'rid:' . $arr['reg_id']);
+ $now = datetime_convert();
+
+ // reg_flags 0x0020 = REGISTER_AGREED = register request verified by user @ regate
+ $register = q("SELECT * FROM register WHERE reg_id = %d AND (reg_flags & 31) = 0 "
+ . " AND reg_startup < '%s' AND reg_expires > '%s' ",
+ intval($arr['reg_id']),
+ dbesc($now),
+ dbesc($now)
+ );
+
+ if ( ! $register ) return $result;
+
+ // account
+ $expires = NULL_DATE;
+
+ $default_service_class = get_config('system','default_service_class');
+ if($default_service_class === false)
+ $default_service_class = '';
+
+ $roles = 0;
+ // prevent form hackery
+ if($roles & ACCOUNT_ROLE_ADMIN) {
+ $admin_result = check_account_admin($arr);
+ if(! $admin_result) {
+ $roles = 0;
+ }
+ }
+
+ // any accounts available ?
+ $isa = q("SELECT COUNT(*) AS isa FROM account");
+ if ($isa && $isa[0]['isa'] == 0) {
+ $roles = ACCOUNT_ROLE_ADMIN;
+ }
+
+ $password_parts = explode(',', $register[0]['reg_pass']);
+ $salt = $password_parts[0];
+ $password_encoded = $password_parts[1];
+
+ $ri = q(
+ "INSERT INTO account ("
+ . " account_parent, account_salt, account_password, account_email, "
+ . " account_language, account_created, account_flags, account_roles, account_level, "
+ . " account_expires, account_service_class) VALUES( "
+ . " %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s' ) ",
+ intval($parent),
+ dbesc($salt),
+ dbesc($password_encoded),
+ dbesc($register[0]['reg_did2']),
+ dbesc($register[0]['reg_lang']),
+ dbesc($now),
+ intval($register[0]['reg_flags'] & 31), // off REGISTER_AGREE at ACCOUNT
+ intval($roles),
+ intval(5),
+ dbesc($expires),
+ dbesc($default_service_class)
+ );
+
+ if(! $ri) {
+ logger('create_account: DB INSERT failed.');
+ $result['message'] = 'ZAR ' . t('Failed to store account information.');
+ return($result);
+ }
+
+ $r = q("SELECT * FROM account WHERE account_email = '%s' AND account_password = '%s' LIMIT 1",
+ dbesc($register[0]['reg_did2']),
+ dbesc($password_encoded)
+ );
+ if($r && count($r)) {
+ $result['account'] = $r[0];
+ }
+ else {
+ logger('create_account: could not retrieve newly created account');
+ }
+
+ // Set the parent record to the current record_id if no parent was provided
+ if(! $parent) {
+ $r = q("UPDATE account SET account_parent = %d WHERE account_id = %d",
+ intval($result['account']['account_id']),
+ intval($result['account']['account_id'])
+ );
+ if(! $r) {
+ logger('create_account: failed to set parent');
+ }
+ $result['account']['parent'] = $result['account']['account_id'];
+ }
+
+ $result['success'] = true;
+
+ //call_hooks('register_account',$result);
+
+ return $result;
+}
+
+/**
+ * @brief as far to see, email validation for register account verification
+ * @param array (account)
+ * @param array ('resend' => true, 'email' = > email)
+ *
+ */
function verify_email_address($arr) {
+ // $hash = random_string(24);
+
+ // [hilmar ->
+ $reg = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_email = 's%' ",
+ dbesc($arr['email'])
+ );
+ if ( ! $reg)
+ return false;
+
+ push_lang(($reg[0]['email']) ? $reg[0]['email'] : 'en');
+
+ $email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'),
+ [
+ '$sitename' => get_config('system','sitename'),
+ '$siteurl' => z_root(),
+ '$email' => $arr['email'],
+ '$uid' => 1,
+ '$hash' => $hash,
+ '$details' => ''
+ ]
+ );
+
+ $res = z_mail(
+ [
+ 'toEmail' => $arr['email'],
+ 'messageSubject' => sprintf( t('Registration confirmation for %s'), get_config('system','sitename')),
+ 'textVersion' => $email_msg,
+ ]
+ );
+
+ pop_lang();
+
+ if(! $res)
+ logger('send_reg_approval_email: failed to account_id: ' . $arr['account']['account_id']);
+
+ return $res;
+}
+
+function verify_email_addressNOP($arr) {
+
if(array_key_exists('resend',$arr)) {
$a = q("select * from account where account_email = '%s' limit 1",
dbesc($arr['email'])
@@ -271,11 +444,14 @@ function verify_email_address($arr) {
return false;
}
$account = $a[0];
- $v = q("select * from register where uid = %d and password = 'verify' limit 1",
+ // [hilmar ->
+ $v = q("SELECT * FROM register WHERE reg_uid = %d AND reg_vital = 1 "
+ . " AND reg_pass = 'verify' LIMIT 1",
intval($account['account_id'])
);
+ // <- hilmar]
if($v) {
- $hash = $v[0]['hash'];
+ $hash = $v[0]['reg_hash'];
}
else {
return false;
@@ -284,13 +460,16 @@ function verify_email_address($arr) {
else {
$hash = random_string(24);
- q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
+ // [hilmar ->
+ q("INSERT INTO register ( reg_hash, reg_created, reg_uid, reg_pass, reg_lang, reg_stuff ) "
+ ." VALUES ( '%s', '%s', %d, '%s', '%s', '' ) ",
dbesc($hash),
dbesc(datetime_convert()),
intval($arr['account']['account_id']),
dbesc('verify'),
dbesc($arr['account']['account_language'])
);
+ // <- hilmar]
$account = $arr['account'];
}
@@ -347,11 +526,17 @@ function send_reg_approval_email($arr) {
$hash = random_string();
- $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
+ // [hilmar ->
+ // code before fetches the $admins as recipients for the approval request mail
+ // $arr has a user (self registered) account
+ // ... $arr['email'] ???
+ // ... reg expiration ?
+ $r = q("INSERT INTO register ( reg_hash, reg_email, reg_created, reg_uid, reg_pass, reg_lang, reg_stuff )"
+ . " VALUES ( '%s', '%s', '%s', %d, '', '%s', '' ) ",
dbesc($hash),
+ dbesc($arr['account']['account_email']),
dbesc(datetime_convert()),
intval($arr['account']['account_id']),
- dbesc(''),
dbesc($arr['account']['account_language'])
);
@@ -425,7 +610,7 @@ function account_allow($hash) {
$ret = array('success' => false);
- $register = q("SELECT * FROM register WHERE hash = '%s' LIMIT 1",
+ $register = q("SELECT * FROM register WHERE reg_hash = '%s' LIMIT 1",
dbesc($hash)
);
@@ -433,57 +618,89 @@ function account_allow($hash) {
return $ret;
$account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
+ // a register entry without account assigned to
if(! $account)
return $ret;
- q("DELETE FROM register WHERE hash = '%s'",
- dbesc($register[0]['hash'])
+ // [hilmar ->
+
+ q("START TRANSACTION");
+ //q("DELETE FROM register WHERE reg_hash = '%s'",
+ // dbesc($register[0]['reg_hash'])
+ //);
+ $r1 = q("UPDATE register SET reg_vital = 0 WHERE reg_hash = '%s'",
+ dbesc($register[0]['reg_hash'])
);
- q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+ /* instead of ...
+
+ // unblock
+ q("UPDATE account SET account_flags = (account_flags & ~%d) "
+ . " WHERE (account_flags & %d)>0 AND account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
- q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
+ // unpend
+ q("UPDATE account SET account_flags = (account_flags & ~%d) "
+ . " WHERE (account_flags & %d)>0 AND account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
- push_lang($register[0]['lang']);
+ */
+ // together unblock and unpend
+ $r2 = q("UPDATE account SET account_flags = %d WHERE account_id = %d",
+ intval($account['account_flags']
+ &= $account['account_flags'] ^ (ACCOUNT_BLOCKED | ACCOUNT_PENDING)),
+ intval($register[0]['reg_uid'])
+ );
- $email_tpl = get_intltext_template("register_open_eml.tpl");
- $email_msg = replace_macros($email_tpl, array(
- '$sitename' => get_config('system','sitename'),
- '$siteurl' => z_root(),
- '$username' => $account[0]['account_email'],
- '$email' => $account[0]['account_email'],
- '$password' => '',
- '$uid' => $account[0]['account_id']
- ));
+ if($r1 && $r2) {
+ q("COMMIT");
- $res = z_mail(
- [
- 'toEmail' => $account[0]['account_email'],
- 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')),
- 'textVersion' => $email_msg,
- ]
- );
+ // <- hilmar]
- pop_lang();
+ push_lang($register[0]['reg_lang']);
- if(get_config('system','auto_channel_create'))
- auto_channel_create($register[0]['uid']);
+ $email_tpl = get_intltext_template("register_open_eml.tpl");
+ $email_msg = replace_macros($email_tpl, array(
+ '$sitename' => get_config('system','sitename'),
+ '$siteurl' => z_root(),
+ '$username' => $account[0]['account_email'],
+ '$email' => $account[0]['account_email'],
+ '$password' => '',
+ '$uid' => $account[0]['account_id']
+ ));
- if ($res) {
- info( t('Account approved.') . EOL );
- return true;
+ $res = z_mail(
+ [
+ 'toEmail' => $account[0]['account_email'],
+ 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')),
+ 'textVersion' => $email_msg,
+ ]
+ );
+
+ pop_lang();
+
+ if(get_config('system', 'auto_channel_create', 1))
+ auto_channel_create($register[0]['uid']);
+
+ if ($res) {
+ info( t('Account approved.') . EOL );
+ return true;
+ }
+
+ // [hilmar ->
+ } else {
+ q("ROLLBACK");
}
+ // <- hilmar]
}
@@ -500,42 +717,65 @@ function account_allow($hash) {
function account_deny($hash) {
- $register = q("SELECT * FROM register WHERE hash = '%s' LIMIT 1",
+ // [hilmar->
+ $register = q("SELECT * FROM register WHERE reg_hash = '%s' AND reg_vital = 1 LIMIT 1",
dbesc($hash)
);
+ // <-hilmar]
if(! count($register))
return false;
$account = q("SELECT account_id, account_email FROM account WHERE account_id = %d LIMIT 1",
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
if(! $account)
return false;
- q("DELETE FROM account WHERE account_id = %d",
- intval($register[0]['uid'])
- );
+ // [hilmar ->
+ q("START TRANSACTION");
- q("DELETE FROM register WHERE id = %d",
- dbesc($register[0]['id'])
+ $r1 = q("DELETE FROM account WHERE account_id = %d",
+ intval($register[0]['reg_uid'])
+ );
+ // q("DELETE FROM register WHERE reg_id = %d",
+ // dbesc($register[0]['reg_id'])
+ //);
+ $r2 = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND reg_vital = 1",
+ dbesc($register[0]['reg_id'])
);
- notice( sprintf(t('Registration revoked for %s'), $account[0]['account_email']) . EOL);
- return true;
+ if($r1 && $r2) {
+ q("COMMIT");
+ notice( 'ZAR0512I,' . sprintf( t('Registration revoked for %s'),
+ $account[0]['account_email']) . EOL);
+ return true;
-}
+ } else {
-// called from regver to activate an account from the email verification link
+ q("ROLLBACK");
+ notice( 'ZAR0513F,' . sprintf( t('Could not revoke registration for %s'),
+ $account[0]['account_email']) . EOL);
+ return false;
+ }
+ // <- hilmar]
+}
+/**
+ * called from Regver to allow/revoke an account
+ * Use case is under REGISTER_OPEN with APPROVAL
+ * Ref Regver, Email_validation, Email_resend
+ * ZAR052+
+ */
function account_approve($hash) {
$ret = false;
// Note: when the password in the register table is 'verify', the uid actually contains the account_id
+ // hmm
- $register = q("SELECT * FROM register WHERE hash = '%s' and password = 'verify' LIMIT 1",
+ $register = q("SELECT * FROM register WHERE reg_hash = '%s' and reg_pass = 'verify' LIMIT 1",
dbesc($hash)
);
@@ -543,45 +783,58 @@ function account_approve($hash) {
return $ret;
$account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
if(! $account)
return $ret;
- q("DELETE FROM register WHERE hash = '%s' and password = 'verify'",
- dbesc($register[0]['hash'])
+ // tr ?
+
+ q("DELETE FROM register WHERE reg_hash = '%s' and reg_pass = 'verify'",
+ dbesc($register[0]['reg_hash'])
);
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_UNVERIFIED),
intval(ACCOUNT_UNVERIFIED),
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
+ /*
+ // together unblock unpend and verified
+ q("UPDATE account SET account_flags = %d WHERE account_id = %d",
+ intval($account['account_flags']
+ &= $account['account_flags']
+ ^ (ACCOUNT_BLOCKED | ACCOUNT_PENDING | ACCOUNT_UNVERIFIED)),
+ intval($register[0]['reg_uid'])
+ );
+ */
+
+
// get a fresh copy after we've modified it.
$account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
- intval($register[0]['uid'])
+ intval($register[0]['reg_uid'])
);
if(! $account)
return $ret;
if(get_config('system','auto_channel_create'))
- auto_channel_create($register[0]['uid']);
+ auto_channel_create($register[0]['reg_uid']);
else {
$_SESSION['login_return_url'] = 'new_channel';
authenticate_success($account[0],null,true,true,false,true);
@@ -591,6 +844,118 @@ function account_approve($hash) {
}
+function verify_register_scheme() {
+
+ $dbc = db_columns('register');
+ if ($dbc) {
+
+ if ($dbc[0]=='id') {
+ // v1 format
+ q("START TRANSACTION");
+
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ $r1 = q("ALTER TABLE register RENAME TO register100;");
+
+ $r2 = q("CREATE TABLE register ("
+ . "reg_id serial NOT NULL,"
+ . "reg_vital int DEFAULT 1 NOT NULL,"
+ . "reg_flags bigint DEFAULT 0 NOT NULL,"
+ . "reg_didx char(1) DEFAULT '' NOT NULL,"
+ . "reg_did2 text DEFAULT '' NOT NULL,"
+ . "reg_hash text DEFAULT '' NOT NULL,"
+ . "reg_email text DEFAULT '' NOT NULL,"
+ . "reg_created timestamp NOT NULL,"
+ . "reg_startup timestamp NOT NULL,"
+ . "reg_expires timestamp NOT NULL,"
+ . "reg_byc bigint DEFAULT 0 NOT NULL,"
+ . "reg_uid bigint DEFAULT 0 NOT NULL,"
+ . "reg_atip text DEFAULT '' NOT NULL,"
+ . "reg_pass text DEFAULT '' NOT NULL,"
+ . "reg_lang varchar(16) DEFAULT '' NOT NULL,"
+ . "reg_stuff text NOT NULL,"
+ . "PRIMARY KEY (reg_id) );"
+ );
+ $r0 = q("CREATE INDEX ix_reg_vital ON register (reg_vital);");
+ $r0 = q("CREATE INDEX ix_reg_flags ON register (reg_flags);");
+ $r0 = q("CREATE INDEX ix_reg_didx ON register (reg_didx);");
+ $r0 = q("CREATE INDEX ix_reg_did2 ON register (reg_did2);");
+ $r0 = q("CREATE INDEX ix_reg_hash ON register (reg_hash);");
+ $r0 = q("CREATE INDEX ix_reg_email ON register (reg_email);");
+ $r0 = q("CREATE INDEX ix_reg_created ON register (reg_created);");
+ $r0 = q("CREATE INDEX ix_reg_startup ON register (reg_startup);");
+ $r0 = q("CREATE INDEX ix_reg_expires ON register (reg_expires);");
+ $r0 = q("CREATE INDEX ix_reg_byc ON register (reg_byc);");
+ $r0 = q("CREATE INDEX ix_reg_uid ON register (reg_uid);");
+ $r0 = q("CREATE INDEX ix_reg_atip ON register (reg_atip);");
+
+ $r3 = q("INSERT INTO register (reg_id, reg_hash, reg_created, reg_uid, reg_pass, reg_lang, reg_stuff) "
+ . "SELECT id, hash, created, uid, password, lang, '' FROM register100;");
+
+ $r4 = q("DROP TABLE register100");
+
+ }
+ else {
+ $r1 = q("RENAME TABLE register TO register100;");
+
+ $r2 = q("CREATE TABLE IF NOT EXISTS register ("
+ . "reg_id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,"
+ . "reg_vital int(10) UNSIGNED NOT NULL DEFAULT 1,"
+ . "reg_flags int(10) UNSIGNED NOT NULL DEFAULT 0,"
+ . "reg_didx char(1) NOT NULL DEFAULT '',"
+ . "reg_did2 char(191) NOT NULL DEFAULT '',"
+ . "reg_hash char(191) NOT NULL DEFAULT '',"
+ . "reg_email char(191) NOT NULL DEFAULT '',"
+ . "reg_created datetime NOT NULL DEFAULT '0001-01-01 00:00:00',"
+ . "reg_startup datetime NOT NULL DEFAULT '0001-01-01 00:00:00',"
+ . "reg_expires datetime NOT NULL DEFAULT '0001-01-01 00:00:00',"
+ . "reg_byc int(10) UNSIGNED NOT NULL DEFAULT 0 ,"
+ . "reg_uid int(10) UNSIGNED NOT NULL DEFAULT 0 ,"
+ . "reg_atip char(191) NOT NULL DEFAULT '',"
+ . "reg_pass char(191) NOT NULL DEFAULT '',"
+ . "reg_lang char(16) NOT NULL DEFAULT '',"
+ . "reg_stuff text NOT NULL,"
+ . "PRIMARY KEY (reg_id),"
+ . "KEY ix_reg_hash (reg_hash),"
+ . "KEY ix_reg_vital (reg_vital),"
+ . "KEY ix_reg_flags (reg_flags),"
+ . "KEY ix_reg_didx (reg_didx),"
+ . "KEY ix_reg_did2 (reg_did2),"
+ . "KEY ix_reg_email (reg_email),"
+ . "KEY ix_reg_created (reg_created),"
+ . "KEY ix_reg_startup (reg_startup),"
+ . "KEY ix_reg_expires (reg_expires),"
+ . "KEY ix_reg_byc (reg_byc),"
+ . "KEY ix_reg_uid (reg_uid),"
+ . "KEY ix_reg_atip (reg_atip)"
+ . ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
+ );
+
+ $r3 = q("INSERT INTO register (reg_id, reg_hash, reg_created, reg_uid, reg_pass, reg_lang, reg_stuff) "
+ . "SELECT id, hash, created, uid, password, lang, '' FROM register100;");
+
+ $r4 = q("DROP TABLE register100");
+ }
+
+ // $r = ($r1 && $r2 && $r3 && $r4);
+ // the only important
+ $r = $r2;
+
+ if($r) {
+ q("COMMIT");
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+ }
+ elseif ( count($dbc) != 16 ) {
+ // ffu
+ // fields in v2.0.0 = 16
+ }
+ }
+}
+
+
/**
* @brief Checks for accounts that have past their expiration date.
*
@@ -828,3 +1193,89 @@ function get_account_techlevel($account_id = 0) {
return (5);
}
+
+function zar_log($msg='') {
+ file_put_contents('./zar.log',
+ date('Y-m-d_H:i:s') . ' ' . $msg . ', ip: § ' . $_SERVER['REMOTE_ADDR'] . ' §' . "\n", FILE_APPEND);
+ return;
+}
+
+function zar_reg_mail($reonar=false) {
+ if ($reonar) {
+ $zem = z_mail(
+ [
+ 'toEmail' => $reonar['to'],
+ 'fromName' => ' ',
+ 'fromEmail' => $reonar['from'],
+ 'messageSubject' => $reonar['subject'],
+ 'textVersion' => $reonar['txttemplate'],
+ ]
+ );
+ return $zem;
+ }
+}
+
+/**
+ * ckeck current day and time against register duties
+ *
+ * @author Hilmar Runge
+ * @since 2020-02-25
+ * @param the current date and time is taken as default
+ * @return ['isduty'] true/false
+ * ['nowfmt'] the textmsg about the current state
+ * ['atform'] the disabled html attribute for form input fields
+ *
+ */
+function zar_register_dutystate( $now=NULL, $day=NULL ) {
+
+ is_null($now) ? $now = date('Hi') : '';
+ is_null($day) ? $day = date('N') : '';
+
+ $isduty = zarIsDuty($day, $now, 'isOpen');
+
+ if ( $isduty === false ) {
+ return array( 'isduty' => $isduty, 'nowfmt' => '', 'atform' => '' );
+ }
+
+ $dutyis = $isduty ? t('open') : t('closed');
+ $atform = $isduty ? '' : 'disabled';
+ $utc_now = datetime_convert(date_default_timezone_get(), 'UTC', $now, 'c');
+
+ $nowfmt = '';
+
+ if (!$isduty) {
+ $nowfmt = t('Registration is currently');
+ $nowfmt .= ' (<span data-utc="' . $utc_now . '" class="register_date">' . $utc_now . '</span>) ';
+ $nowfmt .= $dutyis . ',<br>';
+
+ $pernext = zarIsDuty($day, $now, 'nextOpen');
+ $week_days = ['','monday','tuesday','wednesday','thursday','friday','saturday','sunday'];
+ $utc_next_open = datetime_convert(date_default_timezone_get(), 'UTC', $week_days[$pernext[0]] . ' ' . $pernext[1], 'c');
+
+ if (is_array($pernext)) {
+ $nowfmt .= t('please come back');
+ $nowfmt .= ' <span data-utc="' . $utc_next_open . '" class="register_date">' . $utc_next_open . '</span>.';
+ }
+ }
+ return array( 'isduty' => $isduty, 'nowfmt' => $nowfmt, 'atform' => $atform);
+
+}
+
+function get_pending_accounts() {
+
+ /* get pending */
+ // [hilmar ->
+ //~ $r = q("SELECT account.*, reg_hash FROM account LEFT JOIN register ON account_id = reg_uid WHERE reg_vital = 1 AND (account_flags & %d) > 0",
+ //~ intval(ACCOUNT_PENDING)
+ //~ );
+
+ // better useability at the moment to tell all (ACCOUNT_PENDING >= 0) instead of (> 0 for those need approval)
+
+ $r = q("SELECT reg_did2, reg_created, reg_startup, reg_expires, reg_email, reg_atip, reg_hash, reg_id, reg_stuff
+ FROM register WHERE reg_vital = 1 AND (reg_flags & %d) = 0 AND (reg_flags & %d) >= 0",
+ intval(ACCOUNT_UNVERIFIED),
+ intval(ACCOUNT_PENDING)
+ );
+
+ return $r;
+}
diff --git a/include/bbcode.php b/include/bbcode.php
index 388a828c4..228af7faa 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -1113,6 +1113,13 @@ function bbcode($Text, $options = []) {
$Text = preg_replace_callback("/\[summary\](.*?)\[\/summary\]/ism", 'bb_spacefy',$Text);
}
+ if (strpos($Text,'[/img]') !== false) {
+ $Text = preg_replace_callback('/\[img(.*?)\[\/(img)\]/ism','\red_escape_codeblock',$Text);
+ }
+ if (strpos($Text,'[/zmg]') !== false) {
+ $Text = preg_replace_callback('/\[zmg(.*?)\[\/(zmg)\]/ism','\red_escape_codeblock',$Text);
+ }
+
$Text = bb_format_attachdata($Text);
// If we find any event code, turn it into an event.
@@ -1236,6 +1243,8 @@ function bbcode($Text, $options = []) {
if($tryoembed) {
$Text = preg_replace_callback("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
}
+ // Is this still desired?
+ // We already turn naked URLs into links during creation time cleanup_bbcode()
$Text = preg_replace("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
}
@@ -1498,9 +1507,21 @@ function bbcode($Text, $options = []) {
"<span class=".'"bb-quote"'.">" . $t_wrote . "</span><blockquote>$2</blockquote>",
$Text);
+
// Images
+
+ if (strpos($Text,'[/img]') !== false) {
+ $Text = preg_replace_callback('/\[\$b64img(.*?)\[\/(img)\]/ism','\red_unescape_codeblock',$Text);
+ }
+
+ if (strpos($Text,'[/zmg]') !== false) {
+ $Text = preg_replace_callback('/\[\$b64zmg(.*?)\[\/(zmg)\]/ism','\red_unescape_codeblock',$Text);
+ }
+
+
// [img]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
+
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" loading="eager" />', $Text);
}
// [img=pathtoimage]image description[/img]
diff --git a/include/datetime.php b/include/datetime.php
index ef0927ea4..4c7105138 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -534,3 +534,39 @@ function update_birthdays() {
}
}
}
+
+/**
+ *
+ * Calculate a due by interval
+ * based on the current datetime the interval is added/subtracted
+ * @author Hilmar Runge
+ * @since 2020-02-20
+ * @param $duri the interval in the format n[n]i
+ * where n is a 1-2 digit numeric amount and i is a unit
+ * example $duri='1w' represents one week
+ * unit may be one of i(minutes), h(hours), d(days), w(weeks), m(months, y(years))
+ * @return array['due'] computed datetime in format 'Y-m-d H:i:s'
+ * ['durn'] the amount
+ * ['duru'] the unit
+ * or false
+ */
+ function calculate_adue($duri=false, $sign='+') {
+ if ( preg_match( '/^[0-9]{1,2}[ihdwmy]{1}$/', $duri ) && ($sign == '+' || $sign == '-') ) {
+ $duru = substr( $duri, -1);
+ $durn = substr( $duri, 0, -1);
+
+ if(!$durn)
+ return false;
+
+ $due = date( 'Y-m-d H:i:s', strtotime(
+ '+' . $durn . ' '
+ . str_replace( array(':i',':h',':d',':w',':m',':y'),
+ array('minutes', 'hours', 'days', 'weeks', 'months', 'years'),
+ ( ':'. $duru )
+ )
+ )
+ );
+ return array( 'durn' => $durn, 'duru' => $duru, 'due' => $due);
+ }
+ return false;
+ }
diff --git a/include/features.php b/include/features.php
index e1457604b..584d9cdfb 100644
--- a/include/features.php
+++ b/include/features.php
@@ -146,40 +146,40 @@ function get_features($filtered = true, $level = (-1)) {
t('Conversation'),
/* disable until we agree on how to implemnt this in zot6/activitypub
[
- 'commtag',
- t('Community Tagging'),
+ 'commtag',
+ t('Community Tagging'),
t('Ability to tag existing posts'),
false,
get_config('feature_lock','commtag'),
],
*/
[
- 'emojis',
- t('Emoji Reactions'),
+ 'emojis',
+ t('Emoji Reactions'),
t('Add emoji reaction ability to posts'),
true,
get_config('feature_lock','emojis'),
],
[
- 'dislike',
- t('Dislike Posts'),
+ 'dislike',
+ t('Dislike Posts'),
t('Ability to dislike posts/comments'),
false,
get_config('feature_lock','dislike'),
],
[
- 'star_posts',
- t('Star Posts'),
+ 'star_posts',
+ t('Star Posts'),
t('Ability to mark special posts with a star indicator'),
false,
get_config('feature_lock','star_posts'),
],
-
+
[
- 'reply_to',
- t('Reply on comment'),
+ 'reply_to',
+ t('Reply on comment'),
t('Ability to reply on selected comment'),
false,
get_config('feature_lock','reply_to'),
@@ -211,60 +211,59 @@ function get_features($filtered = true, $level = (-1)) {
t('Add categories to your posts'),
false,
get_config('feature_lock','categories'),
- feature_level('categories',1),
],
[
- 'large_photos',
- t('Large Photos'),
+ 'large_photos',
+ t('Large Photos'),
t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),
false,
get_config('feature_lock','large_photos'),
],
[
- 'content_encrypt',
- t('Even More Encryption'),
+ 'content_encrypt',
+ t('Even More Encryption'),
t('Allow optional encryption of content end-to-end with a shared secret key'),
false,
get_config('feature_lock','content_encrypt'),
],
[
- 'disable_comments',
- t('Disable Comments'),
+ 'disable_comments',
+ t('Disable Comments'),
t('Provide the option to disable comments for a post'),
false,
get_config('feature_lock','disable_comments'),
],
[
- 'delayed_posting',
- t('Delayed Posting'),
+ 'delayed_posting',
+ t('Delayed Posting'),
t('Allow posts to be published at a later date'),
false,
get_config('feature_lock','delayed_posting'),
],
- [
+ [
'content_expire',
t('Content Expiration'),
- t('Remove posts/comments and/or private messages at a future time'),
- false,
+ t('Remove posts/comments and/or private messages at a future time'),
+ false,
get_config('feature_lock','content_expire'),
],
[
- 'suppress_duplicates',
- t('Suppress Duplicate Posts/Comments'),
+ 'suppress_duplicates',
+ t('Suppress Duplicate Posts/Comments'),
t('Prevent posts with identical content to be published with less than two minutes in between submissions.'),
true,
get_config('feature_lock','suppress_duplicates'),
],
[
- 'auto_save_draft',
- t('Auto-save drafts of posts and comments'),
+ 'auto_save_draft',
+ t('Auto-save drafts of posts and comments'),
t('Automatically saves post and comment drafts in local browser storage to help prevent accidental loss of compositions'),
true,
get_config('feature_lock','auto_save_draft'),
@@ -277,8 +276,8 @@ function get_features($filtered = true, $level = (-1)) {
t('Manage'),
[
- 'nav_channel_select',
- t('Navigation Channel Select'),
+ 'nav_channel_select',
+ t('Navigation Channel Select'),
t('Change channels directly from within the navigation dropdown menu'),
false,
get_config('feature_lock','nav_channel_select'),
@@ -307,8 +306,8 @@ function get_features($filtered = true, $level = (-1)) {
],
[
- 'savedsearch',
- t('Saved Searches'),
+ 'savedsearch',
+ t('Saved Searches'),
t('Save search terms for re-use'),
false,
get_config('feature_lock','savedsearch')
@@ -339,8 +338,8 @@ function get_features($filtered = true, $level = (-1)) {
],
[
- 'forums_tab',
- t('Forum Filter'),
+ 'forums_tab',
+ t('Forum Filter'),
t('Ability to display only posts of a specific forum'),
false,
get_config('feature_lock','forums_tab')
@@ -401,8 +400,8 @@ function get_features($filtered = true, $level = (-1)) {
[
'multi_profiles',
t('Multiple Profiles'),
- t('Ability to create multiple profiles'),
- false,
+ t('Ability to create multiple profiles'),
+ false,
get_config('feature_lock','multi_profiles')
]
@@ -426,7 +425,7 @@ function get_features($filtered = true, $level = (-1)) {
for($y = 0; $y < count($arr[$k]); $y ++) {
$disabled = false;
if(is_array($arr[$k][$y])) {
- if($arr[$k][$y][4] !== false) {
+ if($arr[$k][$y][4] !== false) {
$disabled = true;
}
if(! $disabled) {
@@ -446,7 +445,7 @@ function get_features($filtered = true, $level = (-1)) {
return $narr;
}
-
+
function get_module_features($module) {
$features = get_features(false);
return $features[$module];
diff --git a/include/js_strings.php b/include/js_strings.php
index e06e105fd..ed73b0420 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -116,6 +116,11 @@ function js_strings() {
'$allday' => t('All day','calendar'),
// mod cloud
- '$download_info' => t('Please stand by while your download is being prepared.')
+ '$download_info' => t('Please stand by while your download is being prepared.'),
+
+ // mod register
+ '$email_not_valid' => t('Email address not valid'),
+ '$email_required' => t('Required')
+
));
}
diff --git a/include/security.php b/include/security.php
index 066b1dcf4..f433f8094 100644
--- a/include/security.php
+++ b/include/security.php
@@ -592,10 +592,9 @@ function check_form_security_token($typename = '', $formname = 'form_security_to
$hash = $_REQUEST[$formname];
$max_livetime = 10800; // 3 hours
- $min_livetime = 3; // 3 sec
$x = explode('.', $hash);
- if (time() > (IntVal($x[0]) + $max_livetime) || time() < (IntVal($x[0]) + $min_livetime))
+ if (time() > (IntVal($x[0]) + $max_livetime))
return false;
$sec_hash = hash('whirlpool', App::$observer['xchan_guid'] . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $x[0] . $typename);
@@ -834,3 +833,106 @@ function stream_perms_xchans($perms = NULL) {
return $str;
}
+
+
+/**
+ * Duty day / time checks for account register
+ * @author hilmar runge
+ * @since 2020.02.10
+ * @param $op what to test: isOpen, nextOpen
+ * @param $wd weekday according ISO-8601 (1 monday, 7 sunday)
+ * @param $hhmm a 24h clock value hours and minutes
+ * if no params are given, the values are taken from the current time
+ * return is bool(false) if register_duty is not available
+ */
+function zarIsDuty($wd=NULL, $hhmm=NULL, $op='isOpen') {
+
+ $isduty = get_config('system', 'register_duty_jso');
+
+ if (!$isduty)
+ return (bool)false;
+
+ is_null($wd) ? $wd = date('N') : '';
+ is_null($hhmm) ? $hhmm = date('Hi') : '';
+
+ if (!intval($wd . $hhmm)) return (bool)false;
+
+ // be sure to have a valid weekday as index
+ $wd = (7 + $wd) % 7;
+ $wd === 0 ? $wd = 7 : '';
+
+ $duty = json_decode($isduty, true);
+ if (!$duty)
+ return (bool)false;
+
+ switch ($op) {
+ case 'isOpen':
+ /**
+ * Check if registration is open
+ * @return int(0) for not close (open) or int(1) for closed.
+ * return is bool(false) if register_duty is not available
+ */
+ if (!$duty[$wd]) return (bool)false;
+ $dutyis = 0;
+ foreach ($duty[$wd] as $o => $tf) {
+ if ($o > $hhmm) {
+ $dutyis = $tf;
+ break;
+ }
+ }
+ return $dutyis;
+ break;
+
+ case 'nextOpen':
+ /**
+ * Look for next period opens
+ * @return "=>N =>Hi" date value of the next period register is open for requests
+ * where N is a weekday (1=monday ... 7=sunday) according ISO-8601
+ * where Hi is a 24h clock value hhmm by hours and minutes.
+ * If no next period open is available, return results to false.
+ */
+ $myd = $wd;
+ $myh = $hhmm;
+ $is1 = false;
+
+ // $myd = "5"; // testcase only
+ // $myh = "1110"; // testcase only
+
+ // a 1st match may be applied below my time and is to see as a cycle to the next week
+ // but looking is also for a open time after my time is available this week
+ foreach ($duty as $dd => $dhs) {
+
+ if ($is1 && $dd < $myd)
+ continue;
+
+ foreach ($dhs as $dh => $tf) {
+
+ if ($tf) continue; // close
+
+ // a weeks 1st open
+ if (!$is1) $is1 = array($dd, $dh);
+
+ // but is a match after now?
+ //if ($dd == $myd && $myh >= $dh && $myh <= $dh) continue;
+
+ // if the day is not (more) today start find early morning
+ if ($dd > $myd) $myh = "0000";
+
+ // a next period after now in the remainder of the week
+ if ($dd >= $myd && $dh >= $myh && !$tf)
+ return array($dd, $dh);
+ else
+ continue;
+ }
+ }
+ return $is1; // false or array
+ break;
+
+ default:
+ //
+ break;
+ }
+
+}
+
+
diff --git a/include/text.php b/include/text.php
index b24b40d45..749e1fd70 100644
--- a/include/text.php
+++ b/include/text.php
@@ -874,11 +874,7 @@ function get_tags($s) {
// ignore anything in [color= ], because it may contain color codes which are mistaken for tags
$s = preg_replace('/\[color=(.*?)\]/sm','',$s);
- // skip anchors in URL
- $s = preg_replace('/\[url=(.*?)\]/sm','',$s);
-
// match any double quoted tags
-
if(preg_match_all('/([@#\!]\&quot\;.*?\&quot\;)/',$s,$match)) {
foreach($match[1] as $mtch) {
$ret[] = $mtch;
@@ -891,7 +887,6 @@ function get_tags($s) {
}
// match bracket mentions
-
if(preg_match_all('/([@!]\!?\{.*?\})/',$s,$match)) {
foreach($match[1] as $mtch) {
$ret[] = $mtch;
@@ -900,7 +895,6 @@ function get_tags($s) {
// Pull out single word tags. These can be @nickname, @first_last
// and #hash tags.
-
if(preg_match_all('/(?<![a-zA-Z0-9=\pL\/\?\;])([@#\!]\!?[^ \x0D\x0A,;:\?\[\{\&]+)/u',$s,$match)) {
foreach($match[1] as $mtch) {
@@ -924,7 +918,6 @@ function get_tags($s) {
}
// bookmarks
-
if(preg_match_all('/#\^\[(url|zrl)(.*?)\](.*?)\[\/(url|zrl)\]/',$s,$match,PREG_SET_ORDER)) {
foreach($match as $mtch) {
$ret[] = $mtch[0];
@@ -2322,6 +2315,18 @@ function undo_post_tagging($s) {
return $s;
}
+/**
+ * @brief php to js string transfer
+ * Hilmar, 20200227
+ * String values built in php for using as content for js variables become sanitized. Often required
+ * in cases, where some content will be translated by t(any text...) and is furthermore transfered via
+ * templates to the outputted html stream. Redecoding in js not required nor useful.
+ * Apply like: p2j(t('any text\nI will place on a "next line"'));
+ */
+function p2j($string) {
+ return preg_replace('/\r?\n/', '\\n', addslashes($string));
+}
+
function quote_tag($s) {
if(strpos($s,' ') !== false)
return '&quot;' . $s . '&quot;';
@@ -3574,6 +3579,8 @@ function cleanup_bbcode($body) {
$body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','\red_escape_codeblock',$body);
$body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body);
$body = preg_replace_callback('/\[svg(.*?)\[\/(svg)\]/ism','\red_escape_codeblock',$body);
+ $body = preg_replace_callback('/\[img(.*?)\[\/(img)\]/ism','\red_escape_codeblock',$body);
+ $body = preg_replace_callback('/\[zmg(.*?)\[\/(zmg)\]/ism','\red_escape_codeblock',$body);
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
+\,\(\)]+)/ismu", '\nakedoembed', $body);
@@ -3586,6 +3593,8 @@ function cleanup_bbcode($body) {
$body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','\red_unescape_codeblock',$body);
$body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','\red_unescape_codeblock',$body);
$body = preg_replace_callback('/\[\$b64svg(.*?)\[\/(svg)\]/ism','\red_unescape_codeblock',$body);
+ $body = preg_replace_callback('/\[\$b64img(.*?)\[\/(img)\]/ism','\red_unescape_codeblock',$body);
+ $body = preg_replace_callback('/\[\$b64zmg(.*?)\[\/(zmg)\]/ism','\red_unescape_codeblock',$body);
// fix any img tags that should be zmg
@@ -3708,7 +3717,7 @@ function get_forum_channels($uid) {
$xc = ids_to_querystr($x1,'xchan',true);
- $x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . $xc . ") ",
+ $x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . protect_sprintf($xc) . ") ",
intval($uid)
);
@@ -3716,7 +3725,7 @@ function get_forum_channels($uid) {
$sql_extra = (($xf) ? ' and not xchan in (' . $xf . ')' : '');
// private forums
- $x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . $xc . ") $sql_extra ",
+ $x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . protect_sprintf($xc) . ") $sql_extra ",
intval(local_channel())
);
if($x3) {
@@ -3724,7 +3733,7 @@ function get_forum_channels($uid) {
}
// public forums with no permission to post
- $x4 = q("select xchan from abconfig left join xchan on xchan = xchan_hash where chan = %d and cat = 'their_perms' and k in ('post_wall', 'tag_deliver') and v = '0' and xchan in (" . $xc . ") and xchan_pubforum = 1 $sql_extra ",
+ $x4 = q("select xchan from abconfig left join xchan on xchan = xchan_hash where chan = %d and cat = 'their_perms' and k in ('post_wall', 'tag_deliver') and v = '0' and xchan in (" . protect_sprintf($xc) . ") and xchan_pubforum = 1 $sql_extra ",
intval(local_channel())
);
if($x4) {
@@ -3733,7 +3742,7 @@ function get_forum_channels($uid) {
}
- $sql_extra_1 = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
+ $sql_extra_1 = (($xf) ? " and ( xchan_hash in (" . protect_sprintf($xf) . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
$r = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_addr, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 $sql_extra_1 order by xchan_name",
intval($uid)