prepare( 'SELECT null FROM mailbox WHERE username=? AND active = 1;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
if ( ! $user = $stmt->fetch( PDO::FETCH_ASSOC ) ) {
$_SESSION = [];
session_regenerate_id( true );
$_SESSION[ 'csrf_token' ] = sha1( uniqid() );
$msg .= '
'.htmlspecialchars(_('It looks like your user no longer exists!')).'
';
}
}
if ( $_SERVER[ 'REQUEST_METHOD' ] === 'POST' ) {
if ( $_SESSION[ 'csrf_token' ] !== $_POST[ 'csrf_token' ] ?? '' ) {
die( 'Invalid CSRF token' );
}
if ( isset( $_SESSION[ '2fa_code' ] ) ) {
if ( ! empty( $_POST[ '2fa_code' ] ) && $_POST[ '2fa_code' ] === $_SESSION[ '2fa_code' ] ) {
unset( $_SESSION[ '2fa_code' ] );
unset( $_SESSION[ 'pgp_key' ] );
} else {
$msg .= ''.htmlspecialchars(_('Wrong 2FA code')).'
';
}
}
if ( ! isset( $_SESSION[ '2fa_code' ] ) && isset( $_POST[ 'action' ] ) ) {
if ( $_POST[ 'action' ] === 'logout' ) {
$_SESSION = [];
session_regenerate_id( true );
$_SESSION[ 'csrf_token' ] = sha1( uniqid() );
$msg .= ''.htmlspecialchars(_('Successfully logged out')).'
';
} elseif ( $_POST[ 'action' ] === 'login' ) {
$ok = true;
if ( ! check_captcha( $_POST[ 'challenge' ] ?? '', $_POST[ 'captcha' ] ?? '' ) ) {
$ok = false;
$msg .= ''.htmlspecialchars(_('Invalid captcha')).'
';
}
if ( empty( $_POST[ 'user' ] ) || ! preg_match( '/^([^+]+?)(@([^@]+))?$/i', $_POST[ 'user' ], $match ) ) {
$ok = false;
$msg .= ''.htmlspecialchars(_('Invalid username')).'
';
}
if ( $ok ) {
$db = get_db_instance();
$user = $match[ 1 ];
$domain = $match[ 3 ] ?? CLEARNET_SERVER;
$stmt = $db->prepare( 'SELECT target_domain FROM alias_domain WHERE alias_domain = ? AND active=1;' );
$stmt->execute( [ $domain ] );
if ( $tmp = $stmt->fetch( PDO::FETCH_ASSOC ) ) {
$domain = $tmp[ 'target_domain' ];
}
$stmt = $db->prepare( 'SELECT username, password, password_hash_type, tfa, pgp_key FROM mailbox WHERE username = ? AND active = 1;' );
$stmt->execute( [ "$user@$domain" ] );
if ( $tmp = $stmt->fetch( PDO::FETCH_ASSOC ) ) {
if ( empty( $_POST[ 'pwd' ] ) || ! password_verify( $_POST[ 'pwd' ], $tmp[ 'password' ] ) ) {
$ok = false;
$msg .= ''.htmlspecialchars(_('Incorrect username or password')).'
';
} else {
$_SESSION[ 'email_user' ] = $tmp[ 'username' ];
$stmt = $db->prepare( 'UPDATE mailbox SET last_login = ? WHERE username = ? AND active = 1;' );
$stmt->execute( [ time(), $_SESSION[ 'email_user' ] ] );
// update password hash if it's using an old hashing algorithm
if ( $tmp[ 'password_hash_type' ] !== '{ARGON2ID}' ) {
$hash = password_hash( $_POST[ 'pwd' ], PASSWORD_ARGON2ID );
$stmt = $db->prepare( 'UPDATE mailbox SET password_hash_type = "{ARGON2ID}", password = ? WHERE username = ? AND active = 1;' );
$stmt->execute( [ $hash, $_SESSION[ 'email_user' ] ] );
}
if ( $tmp[ 'tfa' ] ) {
$code = bin2hex( random_bytes( 3 ) );
$_SESSION[ '2fa_code' ] = $code;
$_SESSION[ 'pgp_key' ] = $tmp[ 'pgp_key' ];
}
}
} else {
$msg .= ''.htmlspecialchars(_('Incorrect username or password')).'
';
}
}
} elseif ( ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'update_settings' ) {
$alias_goto = '';
if ( isset( $_POST[ 'alias_keep_copy' ] ) ) {
$alias_goto .= $_SESSION[ 'email_user' ] . ',';
}
if ( ! empty( $_POST[ 'alias_to' ] ) ) {
$additional = preg_split( "/[\s,]+/", $_POST[ 'alias_to' ] );
$alias_goto .= validate_email_list( $additional, $msg );
}
$alias_goto = rtrim( $alias_goto, ',' );
$stmt = $db->prepare( 'UPDATE alias SET goto = ?, enforce_tls_in = ? WHERE address = ? AND active = 1;' );
$stmt->execute( [ $alias_goto, ( isset( $_POST[ 'enforce_tls_in' ] ) ? 1 : 0 ), $_SESSION[ 'email_user' ] ] );
$stmt = $db->prepare( 'UPDATE mailbox SET enforce_tls_in = ?, enforce_tls_out = ? WHERE username = ? AND active = 1;' );
$stmt->execute( [ ( isset( $_POST[ 'enforce_tls_in' ] ) ? 1 : 0 ), ( isset( $_POST[ 'enforce_tls_out' ] ) ? 1 : 0 ), $_SESSION[ 'email_user' ] ] );
} elseif ( ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'update_password' ) {
if ( empty( $_POST[ 'pass_update' ] ) || empty( $_POST[ 'pass_update2' ] ) || $_POST[ 'pass_update' ] !== $_POST[ 'pass_update2' ] ) {
$msg .= ''.htmlspecialchars(_('Passwords empty or don\'t match')).'
';
} else {
$hash = password_hash( $_POST[ 'pass_update' ], PASSWORD_ARGON2ID );
$stmt = $db->prepare( 'UPDATE mailbox SET password_hash_type = "{ARGON2ID}", password = ? WHERE username = ? AND active = 1;' );
$stmt->execute( [ $hash, $_SESSION[ 'email_user' ] ] );
$msg .= ''.htmlspecialchars(_('Successfully updated password')).'
';
}
} elseif ( ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'delete_account' ) {
$msg .= ''.htmlspecialchars(_('Warning: This will permenently delete your account and all your data. Anyone can immediately register with this user again. It cannot be reversed. Are you absolutely sure?')).'
';
$msg .= '';
} elseif ( ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'disable_account' ) {
$msg .= ''.htmlspecialchars(_('Warning: This will disable your account for a year and delete all your data. After a year it is available for registrations again. It cannot be reversed. Are you absolutely sure?')).'
';
$msg .= '';
} elseif ( ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'delete_account2' ) {
$stmt = $db->prepare( 'DELETE FROM alias WHERE address = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$stmt = $db->prepare( 'UPDATE mailbox SET active = -2 WHERE username = ? AND active = 1;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$_SESSION = [];
session_regenerate_id( true );
$_SESSION[ 'csrf_token' ] = sha1( uniqid() );
$msg .= ''.htmlspecialchars(_('Successfully deleted account')).'
';
} elseif ( ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'disable_account2' ) {
$stmt = $db->prepare( 'UPDATE alias SET active = 0 WHERE address = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$stmt = $db->prepare( 'UPDATE mailbox SET active = -1 WHERE username = ? AND active = 1;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$_SESSION = [];
session_regenerate_id( true );
$_SESSION[ 'csrf_token' ] = sha1( uniqid() );
$msg .= ''.htmlspecialchars(_('Successfully disabled account')).'
';
} elseif ( isset( $_POST[ 'pgp_key' ] ) && ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'update_pgp_key' ) {
$pgp_key = trim( $_POST[ 'pgp_key' ] );
if ( empty( $pgp_key ) ) {
$msg .= ''.htmlspecialchars(_('Successfully removed the key')).'
';
$stmt = $db->prepare( 'UPDATE mailbox SET pgp_key = "", tfa = 0, pgp_verified = 0 WHERE username = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
} else {
$gpg = gnupg_init();
gnupg_seterrormode( $gpg, GNUPG_ERROR_WARNING );
gnupg_setarmor( $gpg, 1 );
$imported_key = gnupg_import( $gpg, $pgp_key );
if ( ! $imported_key ) {
$msg .= ''.htmlspecialchars(_('There was an error importing the key')).'
';
} else {
$has_this_email = false;
$key_info = gnupg_keyinfo( $gpg, $imported_key[ 'fingerprint' ] );
foreach ( $key_info as $key ) {
foreach ( $key[ 'uids' ] as $uid ) {
if ( $uid[ 'email' ] === $_SESSION[ 'email_user' ] ) {
$has_this_email = true;
break;
}
}
}
if ( $has_this_email ) {
$msg .= ''.htmlspecialchars(_('Successfully imported the key')).'
';
$stmt = $db->prepare( 'UPDATE mailbox SET pgp_key = ?, tfa = 0, pgp_verified = 0 WHERE username = ?;' );
$stmt->execute( [ $pgp_key, $_SESSION[ 'email_user' ] ] );
} else {
$msg .= '' . sprintf( htmlspecialchars(_('Oops, looks like the key is missing this email address as user id. Please add your address "%s" as user ID to your pgp key or create a new key pair.')), htmlspecialchars( $_SESSION[ 'email_user' ] ) ) . '
';
}
}
}
} elseif ( isset( $_POST[ 'enable_2fa_code' ] ) && ! empty( $_SESSION[ 'email_user' ] ) && $_POST[ 'action' ] === 'enable_2fa' ) {
if ( $_POST[ 'enable_2fa_code' ] !== $_SESSION[ 'enable_2fa_code' ] ) {
$msg .= ''.htmlspecialchars(_('Sorry, the code was incorrect')).'
';
} else {
$stmt = $db->prepare( 'UPDATE mailbox SET tfa = 1, pgp_verified = 1 WHERE username = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$msg .= ''.htmlspecialchars(_('Successfully enabled 2FA')).'
';
}
}
}
}
?>
'.htmlspecialchars(_('To login, please decrypt the following PGP encrypted message and confirm the code:')).'';
echo "$encrypted ";
?>
$msg";
if ( empty( $_SESSION[ 'email_user' ] ) ) { ?>
prepare( 'SELECT goto FROM alias WHERE address = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
if ( $tmp = $stmt->fetch( PDO::FETCH_ASSOC ) ) {
$aliases = explode( ',', $tmp[ 'goto' ] );
}
$aliases_to = implode( "\n", array_diff( $aliases, [ $_SESSION[ 'email_user' ] ] ) );
$stmt = $db->prepare( 'SELECT enforce_tls_in, enforce_tls_out FROM mailbox WHERE username = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$tls_status = $stmt->fetch( PDO::FETCH_ASSOC );
?>
prepare( 'SELECT pgp_key, tfa FROM mailbox WHERE username = ?;' );
$stmt->execute( [ $_SESSION[ 'email_user' ] ] );
$pgp_status = $stmt->fetch( PDO::FETCH_ASSOC );
if ( ! empty( $pgp_status[ 'pgp_key' ] ) ) {
if ( $pgp_status[ 'tfa' ] === 1 ) {
echo ''.htmlspecialchars(_('Yay, PGP based 2FA is enabled!')).'
';
} else {
$gpg = gnupg_init();
gnupg_seterrormode( $gpg, GNUPG_ERROR_WARNING );
gnupg_setarmor( $gpg, 1 );
$imported_key = gnupg_import( $gpg, $pgp_status[ 'pgp_key' ] );
if ( $imported_key ) {
$key_info = gnupg_keyinfo( $gpg, $imported_key[ 'fingerprint' ] );
foreach ( $key_info as $key ) {
if ( ! $key[ 'can_encrypt' ] ) {
echo ''.htmlspecialchars(_('Sorry, this key can\'t be used to encrypt a message to you. Your key may have expired or has been revoked.')).'
';
} else {
foreach ( $key[ 'subkeys' ] as $subkey ) {
gnupg_addencryptkey( $gpg, $subkey[ 'fingerprint' ] );
}
}
}
$_SESSION[ 'enable_2fa_code' ] = bin2hex( random_bytes( 3 ) );
if ( $encrypted = gnupg_encrypt( $gpg, _('To enable 2FA, please enter the following code to confirm ownership of your key:'). "\n\n$_SESSION[enable_2fa_code]\n" ) ) {
echo ''.htmlspecialchars(_( 'Enable 2FA')).' ';
echo ''.htmlspecialchars(_('To enable 2FA using your PGP key, please decrypt the following PGP encrypted message and confirm the code:')).'
';
echo "$encrypted ";
?>