diff options
author | Mario <mario@mariovavti.com> | 2021-05-11 11:59:49 +0000 |
---|---|---|
committer | Mario <mario@mariovavti.com> | 2021-05-11 11:59:49 +0000 |
commit | 26e851ff7fc074592f93088dbd96713b22defe8b (patch) | |
tree | e727d9a83590b152ddd63a8c8e7756835c45de4a /include | |
parent | 406ca206347152cf4acbdcb81fc8152d83f99182 (diff) | |
parent | 89ec043ce1183dbae5ff10a994f0f819a8544ba9 (diff) | |
download | volse-hubzilla-26e851ff7fc074592f93088dbd96713b22defe8b.tar.gz volse-hubzilla-26e851ff7fc074592f93088dbd96713b22defe8b.tar.bz2 volse-hubzilla-26e851ff7fc074592f93088dbd96713b22defe8b.zip |
Merge branch '5.6RC'
Diffstat (limited to 'include')
-rw-r--r-- | include/account.php | 619 | ||||
-rw-r--r-- | include/acl_selectors.php | 9 | ||||
-rw-r--r-- | include/bbcode.php | 21 | ||||
-rw-r--r-- | include/bookmarks.php | 2 | ||||
-rw-r--r-- | include/channel.php | 2 | ||||
-rw-r--r-- | include/conversation.php | 9 | ||||
-rw-r--r-- | include/datetime.php | 36 | ||||
-rw-r--r-- | include/event.php | 10 | ||||
-rw-r--r-- | include/features.php | 73 | ||||
-rw-r--r-- | include/feedutils.php | 22 | ||||
-rw-r--r-- | include/html2plain.php | 47 | ||||
-rw-r--r-- | include/hubloc.php | 50 | ||||
-rw-r--r-- | include/import.php | 5 | ||||
-rw-r--r-- | include/items.php | 143 | ||||
-rw-r--r-- | include/js_strings.php | 7 | ||||
-rw-r--r-- | include/menu.php | 2 | ||||
-rw-r--r-- | include/network.php | 12 | ||||
-rw-r--r-- | include/photo/photo_driver.php | 3 | ||||
-rw-r--r-- | include/queue_fn.php | 2 | ||||
-rw-r--r-- | include/security.php | 106 | ||||
-rw-r--r-- | include/taxonomy.php | 10 | ||||
-rw-r--r-- | include/text.php | 73 |
22 files changed, 1015 insertions, 248 deletions
diff --git a/include/account.php b/include/account.php index fefe61d15..d138dab41 100644 --- a/include/account.php +++ b/include/account.php @@ -34,18 +34,29 @@ function check_account_email($email) { if(! strlen($email)) return $result; - if(! validate_email($email)) - $result['message'] .= t('Not a valid email address') . EOL; - elseif(! allowed_email($email)) - $result['message'] = t('Your email domain is not among those allowed on this site'); + if(! validate_email($email)) { + $result['message'] = t('The provided email address is not valid'); + } + elseif(! allowed_email($email)) { + $result['message'] = t('The provided email domain is not among those allowed on this site'); + } else { - $r = q("select account_email from account where account_email = '%s' limit 1", + $account = q("select account_email from account where account_email = '%s' limit 1", dbesc($email) ); - if($r) { - $result['message'] .= t('Your email address is already registered at this site.'); + if ($account) { + $result['message'] = t('The provided email address is already registered at this site'); + } + + $register = q("select reg_did2 from register where reg_vital = 1 and reg_did2 = '%s' limit 1", + dbesc($email) + ); + if ($register) { + $result['message'] = t('There is a pending registration for this address - click "Register" to continue verification'); + $result['email_unverified'] = true; } } + if($result['message']) $result['error'] = true; @@ -71,17 +82,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 +131,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 +154,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 +292,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 +455,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 +471,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 +537,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 +621,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 +629,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 +728,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 +794,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 +855,118 @@ function account_approve($hash) { } +function verify_register_scheme() { + + $dbc = db_columns('register'); + if ($dbc) { + + if ($dbc[0]=='id') { + // v1 format + dbq("START TRANSACTION"); + + if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = dbq("ALTER TABLE register RENAME TO register100;"); + + $r2 = dbq("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 DEFAULT '0001-01-01 00:00:00'," + . "reg_startup timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'," + . "reg_expires timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'," + . "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 = dbq("CREATE INDEX ix_reg_vital ON register (reg_vital);"); + $r0 = dbq("CREATE INDEX ix_reg_flags ON register (reg_flags);"); + $r0 = dbq("CREATE INDEX ix_reg_didx ON register (reg_didx);"); + $r0 = dbq("CREATE INDEX ix_reg_did2 ON register (reg_did2);"); + $r0 = dbq("CREATE INDEX ix_reg_hash ON register (reg_hash);"); + $r0 = dbq("CREATE INDEX ix_reg_email ON register (reg_email);"); + $r0 = dbq("CREATE INDEX ix_reg_created ON register (reg_created);"); + $r0 = dbq("CREATE INDEX ix_reg_startup ON register (reg_startup);"); + $r0 = dbq("CREATE INDEX ix_reg_expires ON register (reg_expires);"); + $r0 = dbq("CREATE INDEX ix_reg_byc ON register (reg_byc);"); + $r0 = dbq("CREATE INDEX ix_reg_uid ON register (reg_uid);"); + $r0 = dbq("CREATE INDEX ix_reg_atip ON register (reg_atip);"); + + $r3 = dbq("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 = dbq("DROP TABLE register100"); + + } + else { + $r1 = dbq("RENAME TABLE register TO register100;"); + + $r2 = dbq("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 = dbq("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 = dbq("DROP TABLE register100"); + } + + // $r = ($r1 && $r2 && $r3 && $r4); + // the only important + $r = $r2; + + if($r) { + dbq("COMMIT"); + return UPDATE_SUCCESS; + } + + dbq("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 +1204,100 @@ function get_account_techlevel($account_id = 0) { return (5); } + +function zar_log($msg='') { + + if(get_config('system', 'register_logfile', 0)) { + file_put_contents('./zar.log', + date('Y-m-d_H:i:s') . ' ' . $msg . ', ip: § ' . $_SERVER['REMOTE_ADDR'] . ' §' . "\n", FILE_APPEND); + } + else { + logger('zar_log: ' . $msg . ', ip: § ' . $_SERVER['REMOTE_ADDR'] . ' §'); + } + + 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_all = false) { + + $sql_extra = " AND (reg_flags & " . ACCOUNT_UNVERIFIED . ") = 0 "; + + if($get_all) + $sql_extra = ''; + + $r = q("SELECT reg_did2, reg_created, reg_startup, reg_expires, reg_email, reg_atip, reg_hash, reg_id, reg_flags, reg_stuff + FROM register WHERE reg_vital = 1 $sql_extra AND (reg_flags & %d) >= 0", + intval(ACCOUNT_PENDING) + ); + + return $r; +} + +function remove_expired_registrations() { + q("DELETE FROM register WHERE (reg_expires < '%s' OR reg_expires = '%s') AND (reg_flags & %d) > 0", + dbesc(datetime_convert()), + dbesc(NULL_DATE), + dbesc(ACCOUNT_UNVERIFIED) + ); +} diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 8da46649c..f158a439b 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -63,6 +63,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti $single_group = false; $just_me = false; $custom = false; + $groups = ''; if($allow_cid || $allow_gid || $deny_gid || $deny_cid) { $has_acl = true; @@ -112,11 +113,11 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti $forums_count = 0; $forum_otions = ''; foreach($forums as $f) { - if($f['no_post_perms']) + if(isset($f['no_post_perms'])) continue; - $private = (($f['private_forum']) ? ' (' . t('Private Forum') . ')' : ''); - $selected = (($single_group && $f['hash'] === $allow_cid[0]) ? ' selected = "selected" ' : ''); + $private = ((isset($f['private_forum'])) ? ' (' . t('Private Forum') . ')' : ''); + $selected = (($single_group && isset($f['hash'], $allow_cid[0]) && $f['hash'] === $allow_cid[0]) ? ' selected = "selected" ' : ''); $forum_otions .= '<option id="^' . $f['abook_id'] . '" value="^' . $f['xchan_hash'] . '"' . $selected . '>' . $f['xchan_name'] . $private . '</option>' . "\r\n"; $forums_count++; } @@ -133,7 +134,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti $o = replace_macros($tpl, array( '$showall' => $showall_caption, '$onlyme' => t('Only me'), - '$groups' => $groups, + '$groups' => $groups, '$public_selected' => (($has_acl) ? false : true), '$justme_selected' => $just_me, '$custom_selected' => $custom, 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/bookmarks.php b/include/bookmarks.php index 145119347..207cf5a33 100644 --- a/include/bookmarks.php +++ b/include/bookmarks.php @@ -73,6 +73,6 @@ function get_bookmark_link($observer) { $h = @parse_url($observer['xchan_url']); if($h) - return $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '') . '/rbmark?f='; + return $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '') . '/rbmark?f='; return ''; } diff --git a/include/channel.php b/include/channel.php index 31c7c407f..bc9f686e7 100644 --- a/include/channel.php +++ b/include/channel.php @@ -2593,7 +2593,7 @@ function channelx_by_n($id) { } $r = q("SELECT * FROM channel LEFT JOIN xchan ON channel_hash = xchan_hash WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", - dbesc($id) + intval($id) ); return(($r) ? $r[0] : false); diff --git a/include/conversation.php b/include/conversation.php index ae69b7a01..04aa1ef5a 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -865,7 +865,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa $x = [ 'mode' => $mode, 'item' => $item ]; call_hooks('stream_item',$x); - if($x['item']['blocked']) + if(isset($x['item']['blocked'])) continue; $item = $x['item']; @@ -1313,6 +1313,7 @@ function hz_status_editor($a, $x, $popup = false) { if($c && $c['channel_moved']) return $o; + $webpage = ((x($x,'webpage')) ? $x['webpage'] : ''); $plaintext = true; $feature_nocomment = feature_enabled($x['profile_uid'], 'disable_comments'); @@ -1366,8 +1367,6 @@ function hz_status_editor($a, $x, $popup = false) { else $id_select = ''; - $webpage = ((x($x,'webpage')) ? $x['webpage'] : ''); - $reset = ((x($x,'reset')) ? $x['reset'] : ''); $feature_auto_save_draft = ((feature_enabled($x['profile_uid'], 'auto_save_draft')) ? "true" : "false"); @@ -1563,7 +1562,7 @@ function sort_item_children($items) { $result = $items; usort($result,'sort_thr_created_rev'); foreach($result as $k => $i) { - if($result[$k]['children']) { + if(isset($result[$k]['children'])) { $result[$k]['children'] = sort_item_children($result[$k]['children']); } } @@ -1573,7 +1572,7 @@ function sort_item_children($items) { function add_children_to_list($children, &$arr) { foreach($children as $y) { $arr[] = $y; - if($y['children']) + if(isset($y['children'])) add_children_to_list($y['children'], $arr); } } 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/event.php b/include/event.php index 765086167..440f559da 100644 --- a/include/event.php +++ b/include/event.php @@ -862,15 +862,15 @@ function event_import_ical($ical, $uid) { // we do not have it here since parse_ical_file() is passing the vevent only. $timezone_obj = \Sabre\VObject\TimeZoneUtil::getTimeZone($ical->DTSTART['TZID']); $timezone = $timezone_obj->getName(); - $ev['timezone'] = $timezone; + $ev['timezone'] = (($timezone) ? $timezone : date_default_timezone_get()); } - $ev['dtstart'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),$ev['timezone'], + $ev['dtstart'] = datetime_convert((($ev['adjust']) ? 'UTC' : $ev['timezone']), 'UTC', $dtstart->format(\DateTime::W3C)); if(isset($ical->DTEND)) { $dtend = $ical->DTEND->getDateTime(); - $ev['dtend'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),$ev['timezone'], + $ev['dtend'] = datetime_convert((($ev['adjust']) ? 'UTC' : $ev['timezone']), 'UTC', $dtend->format(\DateTime::W3C)); } else { @@ -1311,9 +1311,9 @@ function event_store_item($arr, $event) { } // propagate the event resource_id so that posts containing it are easily searchable in downstream copies - // of the item which have not stored the actual event. Required for Diaspora event federation as Diaspora + // of the item which have not stored the actual event. Required for Diaspora event federation as Diaspora // event_participation messages refer to the event resource_id as a parent, while out own event attendance - // activities refer to the item message_id as the parent. + // activities refer to the item message_id as the parent. set_iconfig($item_arr, 'system','event_id',$event['event_hash'],true); 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/feedutils.php b/include/feedutils.php index 9cb645ff8..e827bde98 100644 --- a/include/feedutils.php +++ b/include/feedutils.php @@ -324,7 +324,7 @@ function get_atom_author($feed, $item) { // check for a yahoo media element (github etc.) - if(! $author['author_photo']) { + if(! x($author,'author_photo') || ! $author['author_photo']) { $rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA,'thumbnail'); if($rawmedia && $rawmedia[0]['attribs']['']['url']) { $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url'])); @@ -334,7 +334,7 @@ function get_atom_author($feed, $item) { // No photo/profile-link on the item - look at the feed level - if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) { + if(! x($author,'author_link') || ! x($author,'author_photo')) { $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author'); if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; @@ -440,8 +440,7 @@ function get_atom_elements($feed, $item) { $summary = ''; if(($summary) && ((strpos($summary,'<') !== false) || (strpos($summary,'>') !== false))) { - $summary = purify_html($summary); - $summary = html2bbcode($summary); + $summary = html2plain($summary); } @@ -479,13 +478,13 @@ function get_atom_elements($feed, $item) { if($rawedited) $res['edited'] = unxmlify($rawedited[0]['data']); - if((x($res,'edited')) && (! (x($res,'created')))) + if(x($res,'edited') && ! x($res,'created')) $res['created'] = $res['edited']; - if(! $res['created']) + if(! x($res,'created')) $res['created'] = $item->get_date('c'); - if(! $res['edited']) + if(! x($res,'edited')) $res['edited'] = $item->get_date('c'); $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb'); @@ -510,7 +509,7 @@ function get_atom_elements($feed, $item) { } } - $ostatus_protocol = (($ostatus_conversation || $res['verb']) ? true : false); + $ostatus_protocol = ($ostatus_conversation || (x($res,'verb') && $res['verb']) ? true : false); $mastodon = (($item->get_item_tags('http://mastodon.social/schema/1.0','scope')) ? true : false); if($mastodon) { @@ -732,7 +731,7 @@ function get_atom_elements($feed, $item) { if((strpos($type,'audio') === 0) && (strpos($res['body'], ']' . $link . '[/audio]') === false) && (strpos($link,'http') === 0)) { $res['body'] .= "\n\n" . '[audio]' . $link . '[/audio]'; } - + $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title ); } } @@ -1114,7 +1113,8 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $parent_link = $rawthread[0]['attribs']['']['href']; } - logger('in-reply-to: ' . $parent_mid, LOGGER_DEBUG); + if(isset($parent_mid)) + logger('in-reply-to: ' . $parent_mid, LOGGER_DEBUG); if($is_reply) { @@ -1409,7 +1409,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { // if we have everything but a photo, provide the default profile photo - if($author['author_name'] && $author['author_link'] && (! $author['author_photo'])) + if($author['author_name'] && $author['author_link'] && (! x($author,'author_photo') || ! $author['author_photo'])) $author['author_photo'] = z_root() . '/' . get_default_profile_photo(80); if(is_array($contact)) { diff --git a/include/html2plain.php b/include/html2plain.php index 91a1f14cb..bf8581bdb 100644 --- a/include/html2plain.php +++ b/include/html2plain.php @@ -76,28 +76,47 @@ function quotelevel($message, $wraplength = 75) return(implode("\n", $newlines)); } + function collecturls($message) { + $pattern = '/<a.*?href="(.*?)".*?>(.*?)<\/a>/is'; preg_match_all($pattern, $message, $result, PREG_SET_ORDER); - - $urls = array(); - foreach ($result as $treffer) { - // A list of some links that should be ignored - $list = array("/user/", "/tag/", "/group/", "/profile/", "/channel/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/", - "//facebook.com/profile.php?id=", "//plus.google.com/"); - foreach ($list as $listitem) - if (strpos($treffer[1], $listitem) !== false) - $ignore = true; - - if ((strpos($treffer[1], "//plus.google.com/") !== false) and (strpos($treffer[1], "/posts") !== false)) + + $urls = []; + if ($result) { + $ignore = false; + foreach ($result as $treffer) { + // A list of some links that should be ignored + $list = [ + "/user/", + "/tag/", + "/group/", + "/profile/", + "/channel/", + "/search?search=", + "/search?tag=", + "mailto:", + "/u/", + "/node/", + "//facebook.com/profile.php?id=", + "//plus.google.com/" + ]; + foreach ($list as $listitem) + if (strpos($treffer[1], $listitem) !== false) + $ignore = true; + + if ((strpos($treffer[1], "//plus.google.com/") !== false) and (strpos($treffer[1], "/posts") !== false)) $ignore = false; - - if (!$ignore) - $urls[$treffer[1]] = $treffer[1]; + + if (! $ignore) + $urls[$treffer[1]] = $treffer[1]; + } } + return($urls); } + function html2plain($html, $wraplength = 75, $compact = false) { diff --git a/include/hubloc.php b/include/hubloc.php index e803b7852..2cce7a725 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -172,6 +172,46 @@ function remove_obsolete_hublocs() { } } +/** + * @brief Remove duplicate singleton hublocs + * + * This should not actually happen but it appears it does - probably due to race conditions. + * This function will just leave the hubloc with the highest id (latest) + * + * TODO: we should probably do something about that at the DB level. + * + */ +function remove_duplicate_singleton_hublocs() { + $hublocs = dbq("SELECT hubloc_hash, COUNT(hubloc_hash) FROM hubloc WHERE + hubloc_network IN( + 'activitypub', + 'diaspora', + 'friendica-over-diaspora', + 'gnusoc' + ) + GROUP BY hubloc_hash + HAVING COUNT(hubloc_hash) > 1" + ); + + foreach($hublocs as $hubloc) { + $hubloc_hash = $hubloc['hubloc_hash']; + + $max_id = q("select max(hubloc_id) as max_id from hubloc where hubloc_hash = '%s'", + dbesc($hubloc_hash) + ); + + $id = $max_id[0]['max_id']; + + if($hubloc_hash && $id) { + q("delete from hubloc where hubloc_hash = '%s' and hubloc_id != %d", + dbesc($hubloc_hash), + intval($id) + ); + } + } + +} + /** * @brief Change primary hubloc. @@ -191,7 +231,7 @@ function hubloc_change_primary($hubloc) { logger('setting primary: ' . $hubloc['hubloc_url'] . ((intval($hubloc['hubloc_primary'])) ? ' true' : ' false')); - // See if this is a local hubloc and if so update the primary for the corresponding channel record. + // See if this is a local hubloc and if so update the primary for the corresponding channel record. if($hubloc['hubloc_url'] === z_root()) { $r = q("select channel_id from channel where channel_hash = '%s' limit 1", @@ -205,7 +245,7 @@ function hubloc_change_primary($hubloc) { } } - // we only need to proceed further if this particular hubloc is now primary + // we only need to proceed further if this particular hubloc is now primary if(! (intval($hubloc['hubloc_primary']))) { logger('not primary: ' . $hubloc['hubloc_url']); @@ -273,7 +313,7 @@ function hubloc_mark_as_down($posturl) { * * @param string $netid network identity (typically xchan_hash or hubloc_hash) * @return string - */ + */ function locations_by_netid($netid) { @@ -281,7 +321,7 @@ function locations_by_netid($netid) { dbesc($netid) ); - + return array_elm_to_str($locs,'location',', ','trim_and_unpunify'); } @@ -331,7 +371,7 @@ function z6_discover() { if ($q2) { continue; } - // zot6 hubloc not found. + // zot6 hubloc not found. if(strpos($q['site_project'],'hubzilla') !== false && version_compare($q['site_version'],'4.0') >= 0) { // probe and store results - only for zot6 (over-ride the zot default) discover_by_webbie($q['hubloc_addr'],'zot6'); diff --git a/include/import.php b/include/import.php index 42fa2f247..379789109 100644 --- a/include/import.php +++ b/include/import.php @@ -715,11 +715,6 @@ function import_items($channel, $items, $sync = false, $relocate = null) { continue; } - // deprecated - - if(array_key_exists('diaspora_meta',$item)) - unset($item['diaspora_meta']); - if($relocate && $item['mid'] === $item['parent_mid']) { item_url_replace($channel,$item,$relocate['url'],z_root(),$relocate['channel_address']); } diff --git a/include/items.php b/include/items.php index 5aee7a51c..9e2a1c10e 100644 --- a/include/items.php +++ b/include/items.php @@ -758,22 +758,34 @@ function get_item_elements($x,$allow_code = false) { // and not enough info to be able to look you up from your hash - which is the only thing stored with the post. $xchan_hash = import_author_xchan($x['author']); - if($xchan_hash) + if($xchan_hash) { $arr['author_xchan'] = $xchan_hash; - else - return array(); + } + else { + return []; + } // save a potentially expensive lookup if author == owner + $legacy_sig = false; + $owner_hash = ''; + if(isset($x['owner']['id']) && isset($x['owner']['key']) && isset($x['owner']['network']) && $x['owner']['network'] === 'zot6') { + $owner_hash = Libzot::make_xchan_hash($x['owner']['id'], $x['owner']['key']); + } + else { + $owner_hash = make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig']); + $legacy_sig = true; + } - if($arr['author_xchan'] === make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig'])) + if($arr['author_xchan'] === $owner_hash) { $arr['owner_xchan'] = $arr['author_xchan']; + } else { $xchan_hash = import_author_xchan($x['owner']); if($xchan_hash) { $arr['owner_xchan'] = $xchan_hash; } else { - return array(); + return []; } } @@ -793,7 +805,15 @@ function get_item_elements($x,$allow_code = false) { ); if($r) { if($r[0]['xchan_pubkey'] && $r[0]['xchan_network'] === 'zot6') { - if(Libzot::verify($x['body'], $arr['sig'], $r[0]['xchan_pubkey'])) { + $item_verified = false; + if($legacy_sig) { + $item_verified = Crypto::verify($x['body'], base64url_decode($arr['sig']), $r[0]['xchan_pubkey']); + } + else { + $item_verified = Libzot::verify($x['body'], $arr['sig'], $r[0]['xchan_pubkey']); + } + + if($item_verified) { $arr['item_verified'] = 1; } else { @@ -926,23 +946,41 @@ function import_author_xchan($x) { * * \e string \b xchan_hash - Thre returned value */ call_hooks('import_author_xchan', $arr); - if($arr['xchan_hash']) + if($arr['xchan_hash']) { return $arr['xchan_hash']; + } $y = false; - if((! array_key_exists('network', $x)) || ($x['network'] === 'zot')) { + if((isset($x['id']) && isset($x['key'])) && (!isset($x['network']) || $x['network'] === 'zot6')) { + $y = Libzot::import_author_zot($x); + } + + if(!$y && isset($x['url']) && isset($x['network']) && $x['network'] === 'zot6') { + $r = q("SELECT xchan_hash FROM xchan WHERE xchan_url = '%s' AND xchan_network = 'zot6'", + dbesc($x['url']) + ); + if($r) + $y = $r[0]['xchan_hash']; + else + $y = discover_by_webbie($x['url'], 'zot6'); + } + + // if we were told that it's a zot6 connection, don't probe/import anything else + + if($y) + return $y; + + if(!$y && !isset($x['network']) || $x['network'] === 'zot') { $y = import_author_zot($x); } - // if we were told that it's a zot connection, don't probe/import anything else - if(array_key_exists('network',$x) && $x['network'] === 'zot') { + if(isset($x['network']) || $x['network'] === 'zot') { if($x['url']) { // check if we already have the zot6 xchan of this xchan_url. if not import it. $r = q("SELECT xchan_hash FROM xchan WHERE xchan_url = '%s' AND xchan_network = 'zot6'", dbesc($x['url']) ); - if(! $r) discover_by_webbie($x['url'], 'zot6'); } @@ -951,10 +989,8 @@ function import_author_xchan($x) { } // perform zot6 discovery - if($x['url']) { - $y = discover_by_webbie($x['url'],'zot6'); - + $y = discover_by_webbie($x['url'], 'zot6'); if($y) { return $y; } @@ -968,7 +1004,7 @@ function import_author_xchan($x) { $y = import_author_unknown($x); } - return($y); + return $y; } /** @@ -1206,10 +1242,10 @@ function encode_item($item,$mirror = false,$zap_compat = false) { else $x['comment_scope'] = $c_scope; - if($item['term']) - $x['tags'] = encode_item_terms($item['term'],$mirror); + if(! empty($item['term'])) + $x['tags'] = encode_item_terms($item['term'],$mirror); - if($item['iconfig']) { + if(! empty($item['iconfig'])) { if ($zap_compat) { for ($y = 0; $y < count($item['iconfig']); $y ++) { if (preg_match('|^a:[0-9]+:{.*}$|s', $item['iconfig'][$y]['v'])) { @@ -1217,7 +1253,7 @@ function encode_item($item,$mirror = false,$zap_compat = false) { } } } - $x['meta'] = encode_item_meta($item['iconfig'],$mirror); + $x['meta'] = encode_item_meta($item['iconfig'],$mirror); } logger('encode_item: ' . print_r($x,true), LOGGER_DATA); @@ -1296,6 +1332,10 @@ function encode_item_xchan($xchan) { $ret['guid'] = $xchan['xchan_guid']; $ret['guid_sig'] = $xchan['xchan_guid_sig']; + $ret['id'] = $xchan['xchan_guid']; + $ret['id_sig'] = $xchan['xchan_guid_sig']; + $ret['key'] = $xchan['xchan_pubkey']; + return $ret; } @@ -1432,7 +1472,7 @@ function purify_imported_object($obj) { elseif (is_string($obj)) { $ret = purify_html($obj); } - + return $ret; } @@ -1690,14 +1730,14 @@ function item_sign(&$item) { if(array_key_exists('sig',$item) && $item['sig']) return; - $r = q("select channel_prvkey from channel where channel_id = %d and channel_hash = '%s' ", + $r = q("select * from channel where channel_id = %d and channel_hash = '%s' ", intval($item['uid']), dbesc($item['author_xchan']) ); if(! $r) return; - $item['sig'] = base64url_encode(Crypto::sign($item['body'], $r[0]['channel_prvkey'])); + $item['sig'] = Libzot::sign($item['body'], $r[0]['channel_prvkey']); $item['item_verified'] = 1; } @@ -2832,11 +2872,11 @@ function tag_deliver($uid, $item_id) { * Now we've got those out of the way. Let's see if this is a post that's tagged for re-delivery */ - $terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM)); - - if($terms) + $terms = []; + if (array_key_exists('term', $item)) { + $terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM)); logger('Post mentions: ' . print_r($terms,true), LOGGER_DATA); - + } $max_forums = get_config('system','max_tagged_forums',2); $matched_forums = 0; @@ -2845,7 +2885,7 @@ function tag_deliver($uid, $item_id) { $link = normalise_link($u[0]['xchan_url']); - if($terms) { + if(count($terms) > 0) { foreach($terms as $term) { if(! link_compare($term['url'],$link)) { continue; @@ -4235,9 +4275,9 @@ function list_post_dates($uid, $wall, $mindate) { $start_month = datetime_convert('','',$dstart,'Y-m-d'); $end_month = datetime_convert('','',$dend,'Y-m-d'); $str = day_translate(datetime_convert('','',$dnow,'F')); - if(! $ret[$dyear]) - $ret[$dyear] = array(); - $ret[$dyear][] = array($str,$end_month,$start_month); + if(! isset($ret[$dyear])) + $ret[$dyear] = []; + $ret[$dyear][] = [ $str, $end_month, $start_month ]; $dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d'); } @@ -4316,17 +4356,17 @@ function fetch_post_tags($items, $link = false) { foreach($tags as $t) { if(($link) && ($t['ttype'] == TERM_MENTION)) $t['url'] = chanlink_url($t['url']); - if(array_key_exists('item_id',$items[$x])) { + if(array_key_exists('item_id', $items[$x])) { if($t['oid'] == $items[$x]['item_id']) { - if(! is_array($items[$x]['term'])) - $items[$x]['term'] = array(); + if(array_key_exists('term', $items[$x]) && ! is_array($items[$x]['term'])) + $items[$x]['term'] = []; $items[$x]['term'][] = $t; } } else { if($t['oid'] == $items[$x]['id']) { - if(! is_array($items[$x]['term'])) - $items[$x]['term'] = array(); + if(array_key_exists('term', $items[$x]) && ! is_array($items[$x]['term'])) + $items[$x]['term'] = []; $items[$x]['term'][] = $t; } } @@ -4336,16 +4376,16 @@ function fetch_post_tags($items, $link = false) { foreach($imeta as $i) { if(array_key_exists('item_id',$items[$x])) { if($i['iid'] == $items[$x]['item_id']) { - if(! is_array($items[$x]['iconfig'])) - $items[$x]['iconfig'] = array(); + if(! isset($items[$x]['iconfig'])) + $items[$x]['iconfig'] = []; $i['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$i['v'])) ? unserialize($i['v']) : $i['v']); $items[$x]['iconfig'][] = $i; } } else { if($i['iid'] == $items[$x]['id']) { - if(! is_array($items[$x]['iconfig'])) - $items[$x]['iconfig'] = array(); + if(array_key_exists('iconfig', $items[$x]) && ! is_array($items[$x]['iconfig'])) + $items[$x]['iconfig'] = []; $i['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$i['v'])) ? unserialize($i['v']) : $i['v']); $items[$x]['iconfig'][] = $i; } @@ -4488,18 +4528,23 @@ function zot_feed($uid, $observer_hash, $arr) { function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = CLIENT_MODE_NORMAL,$module = 'network') { - $result = array('success' => false); - - $sql_extra = ''; - $sql_nets = ''; + $result = ['success' => false]; + $sql_extra = ''; + $sql_nets = ''; $sql_options = ''; - $sql_extra2 = ''; - $sql_extra3 = ''; - $def_acl = ''; - - $item_uids = ' true '; + $sql_extra2 = ''; + $sql_extra3 = ''; + $def_acl = ''; + $item_uids = ' true '; $item_normal = item_normal(); + if (! (isset($arr['include_follow']) && intval($arr['include_follow']))) { + $item_normal .= sprintf(" and not verb in ('%s', '%s') ", + dbesc(ACTIVITY_FOLLOW), + dbesc(ACTIVITY_UNFOLLOW) + ); + } + if($arr['uid']) { $uid = $arr['uid']; } @@ -4861,7 +4906,7 @@ function item_remove_cid($xchan_hash,$mid,$uid) { } // Set item permissions based on results obtained from linkify_tags() -function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, $profile_uid, $parent_item = false, &$private) { +function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, $profile_uid, &$private, $parent_item = false) { $first_access_tag = true; foreach($linkified as $x) { 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/menu.php b/include/menu.php index 88863f57b..02b05a36e 100644 --- a/include/menu.php +++ b/include/menu.php @@ -111,7 +111,7 @@ function menu_render($menu, $class='', $edit = false, $var = array()) { $menu['items'][$x]['mitem_desc'] = zidify_links(smilies(bbcode($menu['items'][$x]['mitem_desc']))); } - $wrap = (($var['wrap'] === 'none') ? false : true); + $wrap = (! x($var, 'wrap') || $var['wrap'] === 'none' ? false : true); $ret = replace_macros(get_markup_template('usermenu.tpl'),array( '$menu' => $menu['menu'], diff --git a/include/network.php b/include/network.php index f5ff48fce..fcc7b4289 100644 --- a/include/network.php +++ b/include/network.php @@ -1134,11 +1134,15 @@ function discover_by_webbie($webbie, $protocol = '') { foreach($x['links'] as $link) { if(array_key_exists('rel',$link)) { if($link['rel'] === PROTOCOL_ZOT6 && ((! $protocol) || (strtolower($protocol) === 'zot6'))) { + logger('zot6 found for ' . $webbie, LOGGER_DEBUG); $record = Zotfinger::exec($link['href']); + if (! $record) { + logger('Record not found for ' . $link['href']); + continue; + } // Check the HTTP signature - $hsig = $record['signature']; if($hsig && $hsig['signer'] === $link['href'] && $hsig['header_valid'] === true && $hsig['content_valid'] === true) $hsig_valid = true; @@ -1226,7 +1230,7 @@ function webfinger_rfc7033($webbie, $zot = false) { if($m['scheme'] !== 'https') return false; - $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + $rhs = $m['host'] . (array_key_exists('port', $m) ? ':' . $m['port'] : ''); $resource = urlencode($webbie); } } @@ -1957,10 +1961,10 @@ function service_plink($contact, $guid) { $m = parse_url($contact['xchan_url']); if($m) { - $url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + $url = $m['scheme'] . '://' . $m['host'] . (array_key_exists('port', $m) ? ':' . $m['port'] : ''); } else { - $url = 'https://' . substr($contact['xchan_addr'],strpos($contact['xchan_addr'],'@')+1); + $url = 'https://' . substr($contact['xchan_addr'], strpos($contact['xchan_addr'], '@') + 1); } $handle = substr($contact['xchan_addr'], 0, strpos($contact['xchan_addr'],'@')); diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index 8de5185af..256369c69 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -239,7 +239,7 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { if($force || empty($modified)) $result = z_fetch_url($photo, true); - elseif($exp - 60 < time()) { + else { $h = []; $h[] = "If-Modified-Since: " . gmdate("D, d M Y H:i:s", $exp) . " GMT"; if(! empty($etag)) @@ -247,6 +247,7 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { $result = z_fetch_url($photo, true, 0, [ 'headers' => $h ]); } + if(isset($result)) { $hdrs = []; $h = explode("\n", $result['header']); diff --git a/include/queue_fn.php b/include/queue_fn.php index b72730d2f..1e8171b1d 100644 --- a/include/queue_fn.php +++ b/include/queue_fn.php @@ -132,7 +132,7 @@ function queue_deliver($outq, $immediate = false) { $base = null; $h = parse_url($outq['outq_posturl']); if($h !== false) - $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); + $base = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : ''); if(($base) && ($base !== z_root()) && ($immediate)) { $y = q("select site_update, site_dead from site where site_url = '%s' ", 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/taxonomy.php b/include/taxonomy.php index 5fa4fde3f..f765a9f0e 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -331,11 +331,11 @@ function pubtagblock($net,$site,$limit,$recent = 0,$safemode = 1, $type = TERM_H } -function pub_tagadelic($net,$site,$limit,$recent,$safemode,$type) { - - $item_normal = item_normal(); - $count = intval($limit); - +function pub_tagadelic($net, $site, $limit, $recent, $safemode, $type) { + + $item_normal = item_normal(); + $count = intval($limit); + $sql_extra = ""; if($site) $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 "; else { diff --git a/include/text.php b/include/text.php index ac22fe565..622c44f14 100644 --- a/include/text.php +++ b/include/text.php @@ -1108,7 +1108,7 @@ function magiclink_url($observer,$myaddr,$url) { function micropro($contact, $redirect = false, $class = '', $mode = false) { - if($contact['click']) + if(x($contact,'click')) $url = '#'; else $url = chanlink_hash($contact['xchan_hash']); @@ -1121,10 +1121,10 @@ function micropro($contact, $redirect = false, $class = '', $mode = false) { $tpl = 'micropro_card.tpl'; return replace_macros(get_markup_template($tpl), array( - '$click' => (($contact['click']) ? $contact['click'] : ''), - '$class' => $class . (($contact['archived']) ? ' archived' : ''), - '$oneway' => (($contact['oneway']) ? true : false), - '$perminfo' => $contact['perminfo'], + '$click' => (x($contact,'click') ? $contact['click'] : ''), + '$class' => $class . (x($contact,'archived') && $contact['archived'] ? ' archived' : ''), + '$oneway' => (x($contact,'oneway') && $contact['oneway'] ? true : false), + '$perminfo' => (x($contact,'perminfo') ? $contact['perminfo'] : ''), '$url' => $url, '$photo' => $contact['xchan_photo_s'], '$name' => $contact['xchan_name'], @@ -1535,39 +1535,46 @@ function unobscure_mail(&$item) { function theme_attachments(&$item) { + $s = ''; $arr = json_decode($item['attach'],true); - if(is_array($arr) && count($arr)) { - $attaches = array(); + + $attaches = []; foreach($arr as $r) { - $icon = getIconFromType($r['type']); + if(isset($r['type'])) + $icon = getIconFromType($r['type']); - if($r['title']) + if(isset($r['title'])) $label = urldecode(htmlspecialchars($r['title'], ENT_COMPAT, 'UTF-8')); - if(! $label && $r['href']) + if(! $label && isset($r['href'])) $label = basename($r['href']); //some feeds provide an attachment where title an empty space if(! $label || $label == ' ') $label = t('Unknown Attachment'); - $title = t('Size') . ' ' . (($r['length']) ? userReadableSize($r['length']) : t('unknown')); + $title = t('Size') . ' ' . (isset($r['length']) ? userReadableSize($r['length']) : t('unknown')); require_once('include/channel.php'); - if(is_foreigner($item['author_xchan'])) - $url = $r['href']; - else - $url = z_root() . '/magic?f=&owa=1&hash=' . $item['author_xchan'] . '&bdest=' . bin2hex($r['href'] . '/' . $r['revision']); + + if (isset($r['href'])) { + if(is_foreigner($item['author_xchan'])) + $url = $r['href']; + else + $url = z_root() . '/magic?f=&owa=1&hash=' . $item['author_xchan'] . '&bdest=' . bin2hex($r['href'] . '/' . $r['revision']); + } //$s .= '<a href="' . $url . '" title="' . $title . '" class="attachlink" >' . $icon . '</a>'; - $attaches[] = array('label' => $label, 'url' => $url, 'icon' => $icon, 'title' => $title); + if (isset($label) && isset($url) && isset($icon) && isset($title)) + $attaches[] = array('label' => $label, 'url' => $url, 'icon' => $icon, 'title' => $title); } - $s = replace_macros(get_markup_template('item_attach.tpl'), array( - '$attaches' => $attaches - )); + if (count($attaches) > 0) + $s = replace_macros(get_markup_template('item_attach.tpl'), [ + '$attaches' => $attaches + ]); } return $s; @@ -1605,8 +1612,8 @@ function format_categories(&$item,$writeable) { */ function format_hashtags(&$item) { - $s = ''; + $s = ''; $terms = get_terms_oftype($item['term'], array(TERM_HASHTAG,TERM_COMMUNITYTAG)); if($terms) { foreach($terms as $t) { @@ -1628,13 +1635,14 @@ function format_hashtags(&$item) { } - function format_mentions(&$item) { - $s = ''; + $s = ''; $terms = get_terms_oftype($item['term'],TERM_MENTION); if($terms) { foreach($terms as $t) { + if(! isset($t['term'])) + continue; $term = htmlspecialchars($t['term'],ENT_COMPAT,'UTF-8',false) ; if(! trim($term)) continue; @@ -2307,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 '"' . $s . '"'; @@ -3559,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); @@ -3571,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 @@ -3676,7 +3700,7 @@ function get_forum_channels($uid) { if(! $uid) return; - if(App::$data['forum_channels']) + if(isset(App::$data['forum_channels'])) return App::$data['forum_channels']; $xf = ''; @@ -3724,6 +3748,9 @@ function get_forum_channels($uid) { intval($uid) ); + if(!$r) + $r = []; + for($x = 0; $x < count($r); $x ++) { if($x3) { foreach($x3 as $xx) { |