mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 08:58:35 +00:00
Removed leftovers
This commit is contained in:
parent
17c555ab6c
commit
57edb4a385
9 changed files with 1 additions and 803 deletions
|
|
@ -1,4 +1,4 @@
|
|||
> [Get started with Appwrite](https://apwr.dev/appcloud)
|
||||
> [Get started with Appwrite](https://apwr.dev/appcloud)
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
|
|
|
|||
194
app/terminal.php
194
app/terminal.php
|
|
@ -1,194 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Utopia\WebSocket\Server;
|
||||
use Utopia\WebSocket\Adapter;
|
||||
use Swoole\Table;
|
||||
use WebSocket\Client;
|
||||
use Utopia\CLI\Console;
|
||||
use Ahc\Jwt\JWT;
|
||||
use Utopia\System\System;
|
||||
|
||||
// WebSocket close codes
|
||||
const CLOSE_NORMAL = 1000; // Normal closure
|
||||
const CLOSE_POLICY_VIOLATION = 1008; // Policy violation or connection lost
|
||||
const CLOSE_SERVER_ERROR = 1011; // Server-side error
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
|
||||
/**
|
||||
* Table for managing runtime connections across all workers.
|
||||
*/
|
||||
$runtimes = new Table(4096, 1);
|
||||
$runtimes->column('userId', Table::TYPE_STRING, 64);
|
||||
$runtimes->column('runtimeHost', Table::TYPE_STRING, 255);
|
||||
$runtimes->column('runtimePort', Table::TYPE_INT);
|
||||
$runtimes->create();
|
||||
|
||||
// Store WebSocket client connections
|
||||
$clients = [];
|
||||
|
||||
const MAX_PACKAGE_LENGTH = 64000;
|
||||
const MAX_RUNTIME_CONNECTIONS = 4096;
|
||||
|
||||
$adapter = new Adapter\Swoole(port: System::getEnv('PORT', 80));
|
||||
$adapter
|
||||
->setPackageMaxLength(MAX_PACKAGE_LENGTH)
|
||||
->setWorkerNumber($workerNumber);
|
||||
|
||||
$server = new Server($adapter);
|
||||
|
||||
$server->onStart(function () use ($workerNumber) {
|
||||
Console::success('Terminal WebSocket Proxy started successfully');
|
||||
Console::info('Listening on port: ' . System::getEnv('PORT', 80));
|
||||
Console::info('Worker processes: ' . $workerNumber);
|
||||
Console::info('Max package length: ' . (MAX_PACKAGE_LENGTH / 1000) . 'KB');
|
||||
Console::info('Max runtime connections: ' . MAX_RUNTIME_CONNECTIONS);
|
||||
});
|
||||
|
||||
$server->onOpen(function (int $connection, $request) use ($server, $runtimes, &$clients) {
|
||||
try {
|
||||
Console::info("New connection: {$connection}");
|
||||
|
||||
// Extract JWT from request
|
||||
$token = $request->header['authorization'] ?? '';
|
||||
if (empty($token)) {
|
||||
throw new Exception('Missing authentication token', 401);
|
||||
}
|
||||
|
||||
// Verify JWT and extract user information
|
||||
$jwt = str_replace('Bearer ', '', $token);
|
||||
$key = System::getEnv('_APP_OPENSSL_KEY_V1', '');
|
||||
$jwt = new JWT($key, 'HS256', 900, 0);
|
||||
|
||||
try {
|
||||
$payload = $jwt->decode($token);
|
||||
$userId = $payload['userId'] ?? '';
|
||||
$sessionId = $payload['sessionId'] ?? '';
|
||||
|
||||
if (empty($userId) || empty($sessionId)) {
|
||||
throw new Exception('Invalid JWT payload', 401);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new Exception('Invalid JWT token', 401);
|
||||
}
|
||||
|
||||
// Get runtime details for user (this could come from your database/cache)
|
||||
$runtimeHost = "runtime-{$userId}.internal"; // Example hostname
|
||||
$runtimePort = 9000;
|
||||
|
||||
// Create WebSocket connection to runtime
|
||||
go(function () use ($server, $connection, &$clients, $runtimeHost, $runtimePort, $userId) {
|
||||
try {
|
||||
// $wsClient = new Client("ws://{$runtimeHost}:{$runtimePort}/", [
|
||||
// 'timeout' => 0, // Disable timeout for long-running connections
|
||||
// 'filter' => ['text', 'binary', 'close'] // Only process these frame types
|
||||
// ]);
|
||||
|
||||
|
||||
$wsClient = new Client(
|
||||
"ws://appwrite-traefik/v1/realtime",
|
||||
[
|
||||
"headers" => [],
|
||||
"timeout" => 30,
|
||||
]
|
||||
);
|
||||
|
||||
// Store client connection
|
||||
$clients[$connection] = [
|
||||
'client' => $wsClient,
|
||||
'userId' => $userId
|
||||
];
|
||||
|
||||
// Forward messages from runtime back to client
|
||||
while (true) {
|
||||
try {
|
||||
$message = $wsClient->receive();
|
||||
if ($message === null) {
|
||||
// Connection closed normally
|
||||
break;
|
||||
}
|
||||
$server->send([$connection], $message);
|
||||
|
||||
// Yield to allow other coroutines to run
|
||||
Swoole\Coroutine::yield();
|
||||
|
||||
} catch (\WebSocket\ConnectionException $e) {
|
||||
Console::error("Runtime connection error for user {$userId}: " . $e->getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup on disconnect
|
||||
$wsClient->close();
|
||||
unset($clients[$connection]);
|
||||
$server->close($connection, CLOSE_NORMAL);
|
||||
} catch (\WebSocket\ConnectionException $e) {
|
||||
Console::error("Failed to connect to runtime for user {$userId}: " . $e->getMessage());
|
||||
$server->close($connection, CLOSE_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Send successful connection message
|
||||
$server->send([$connection], json_encode([
|
||||
'type' => 'connected',
|
||||
'data' => [
|
||||
'userId' => $userId,
|
||||
'timestamp' => time()
|
||||
]
|
||||
]));
|
||||
|
||||
} catch (Throwable $th) {
|
||||
Console::error('Connection error: ' . $th->getMessage());
|
||||
|
||||
$server->send([$connection], json_encode([
|
||||
'type' => 'error',
|
||||
'data' => [
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage()
|
||||
]
|
||||
]));
|
||||
|
||||
$server->close($connection, CLOSE_POLICY_VIOLATION);
|
||||
}
|
||||
});
|
||||
|
||||
$server->onMessage(function (int $connection, string $message) use ($server, &$clients) {
|
||||
try {
|
||||
if (!isset($clients[$connection])) {
|
||||
throw new Exception('Client not connected to runtime', 1008);
|
||||
}
|
||||
|
||||
$wsClient = $clients[$connection]['client'];
|
||||
try {
|
||||
// Forward message to runtime
|
||||
$wsClient->send($message);
|
||||
} catch (\WebSocket\ConnectionException $e) {
|
||||
throw new Exception('Runtime connection lost: ' . $e->getMessage(), 1008);
|
||||
}
|
||||
|
||||
} catch (Throwable $th) {
|
||||
$server->send([$connection], json_encode([
|
||||
'type' => 'error',
|
||||
'data' => [
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage()
|
||||
]
|
||||
]));
|
||||
|
||||
if ($th->getCode() === 1008) {
|
||||
$server->close($connection, CLOSE_POLICY_VIOLATION);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$server->onClose(function (int $connection) use (&$clients) {
|
||||
if (isset($clients[$connection])) {
|
||||
$userId = $clients[$connection]['userId'];
|
||||
$clients[$connection]['client']->close();
|
||||
unset($clients[$connection]);
|
||||
Console::info("Closed connection for user {$userId}");
|
||||
}
|
||||
});
|
||||
|
||||
$server->start();
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* Argon2 accepted options:
|
||||
* int threads
|
||||
* int time_cost
|
||||
* int memory_cost
|
||||
*
|
||||
* Reference: https://www.php.net/manual/en/function.password-hash.php#example-983
|
||||
*/
|
||||
class Argon2 extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
return \password_hash($password, PASSWORD_ARGON2ID, $this->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
return \password_verify($password, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return ['memory_cost' => 65536, 'time_cost' => 4, 'threads' => 3];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* Bcrypt accepted options:
|
||||
* int cost
|
||||
* string? salt; auto-generated if empty
|
||||
*
|
||||
* Reference: https://www.php.net/manual/en/password.constants.php
|
||||
*/
|
||||
class Bcrypt extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
return \password_hash($password, PASSWORD_BCRYPT, $this->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
return \password_verify($password, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'cost' => 8 ];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* MD5 does not accept any options.
|
||||
*
|
||||
* Reference: https://www.php.net/manual/en/function.md5.php
|
||||
*/
|
||||
class Md5 extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
return \md5($password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
return $this->hash($password) === $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Portable PHP password hashing framework.
|
||||
* source Version 0.5 / genuine.
|
||||
* Written by Solar Designer <solar at openwall.com> in 2004-2017 and placed in
|
||||
* the public domain. Revised in subsequent years, still public domain.
|
||||
* There's absolutely no warranty.
|
||||
* The homepage URL for the source framework is: http://www.openwall.com/phpass/
|
||||
* Please be sure to update the Version line if you edit this file in any way.
|
||||
* It is suggested that you leave the main version number intact, but indicate
|
||||
* your project name (after the slash) and add your own revision information.
|
||||
* Please do not change the "private" password hashing method implemented in
|
||||
* here, thereby making your hashes incompatible. However, if you must, please
|
||||
* change the hash type identifier (the "$P$") to something different.
|
||||
* Obviously, since this code is in the public domain, the above are not
|
||||
* requirements (there can be none), but merely suggestions.
|
||||
*
|
||||
* @author Solar Designer <solar@openwall.com>
|
||||
* @copyright Copyright (C) 2017 All rights reserved.
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* PHPass accepted options:
|
||||
* int iteration_count_log2; The Logarithmic cost value used when generating hash values indicating the number of rounds used to generate hashes
|
||||
* string portable_hashes
|
||||
* string random_state; The cached random state
|
||||
*
|
||||
* Reference: https://github.com/photodude/phpass
|
||||
*/
|
||||
class Phpass extends Hash
|
||||
{
|
||||
/**
|
||||
* Alphabet used in itoa64 conversions.
|
||||
*
|
||||
* @var string
|
||||
* @since 0.1.0
|
||||
*/
|
||||
protected string $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
$randomState = \microtime();
|
||||
if (\function_exists('getmypid')) {
|
||||
$randomState .= getmypid();
|
||||
}
|
||||
|
||||
return ['iteration_count_log2' => 8, 'portable_hashes' => false, 'random_state' => $randomState];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
$options = $this->getDefaultOptions();
|
||||
|
||||
$random = '';
|
||||
if (CRYPT_BLOWFISH === 1 && !$options['portable_hashes']) {
|
||||
$random = $this->getRandomBytes(16, $options);
|
||||
$hash = crypt($password, $this->gensaltBlowfish($random, $options));
|
||||
if (strlen($hash) === 60) {
|
||||
return $hash;
|
||||
}
|
||||
}
|
||||
if (strlen($random) < 6) {
|
||||
$random = $this->getRandomBytes(6, $options);
|
||||
}
|
||||
$hash = $this->cryptPrivate($password, $this->gensaltPrivate($random, $options));
|
||||
if (strlen($hash) === 34) {
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returning '*' on error is safe here, but would _not_ be safe
|
||||
* in a crypt(3)-like function used _both_ for generating new
|
||||
* hashes and for validating passwords against existing hashes.
|
||||
*/
|
||||
return '*';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
$verificationHash = $this->cryptPrivate($password, $hash);
|
||||
if ($verificationHash[0] === '*') {
|
||||
$verificationHash = crypt($password, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not constant-time. In order to keep the code simple,
|
||||
* for timing safety we currently rely on the salts being
|
||||
* unpredictable, which they are at least in the non-fallback
|
||||
* cases (that is, when we use /dev/urandom and bcrypt).
|
||||
*/
|
||||
return $hash === $verificationHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
* @throws Exception Thows an Exception if the $count parameter is not a positive integer.
|
||||
*/
|
||||
protected function getRandomBytes(int $count, array $options): string
|
||||
{
|
||||
if (!is_int($count) || $count < 1) {
|
||||
throw new \Exception('Argument count must be a positive integer');
|
||||
}
|
||||
$output = '';
|
||||
if (@is_readable('/dev/urandom') && ($fh = @fopen('/dev/urandom', 'rb'))) {
|
||||
$output = fread($fh, $count);
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
if (strlen($output) < $count) {
|
||||
$output = '';
|
||||
|
||||
for ($i = 0; $i < $count; $i += 16) {
|
||||
$options['iteration_count_log2'] = md5(microtime() . $options['iteration_count_log2']);
|
||||
$output .= md5($options['iteration_count_log2'], true);
|
||||
}
|
||||
|
||||
$output = substr($output, 0, $count);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param int $count
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
* @throws Exception Thows an Exception if the $count parameter is not a positive integer.
|
||||
*/
|
||||
protected function encode64($input, $count)
|
||||
{
|
||||
if (!is_int($count) || $count < 1) {
|
||||
throw new \Exception('Argument count must be a positive integer');
|
||||
}
|
||||
$output = '';
|
||||
$i = 0;
|
||||
do {
|
||||
$value = ord($input[$i++]);
|
||||
$output .= $this->itoa64[$value & 0x3f];
|
||||
if ($i < $count) {
|
||||
$value |= ord($input[$i]) << 8;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 6) & 0x3f];
|
||||
if ($i++ >= $count) {
|
||||
break;
|
||||
}
|
||||
if ($i < $count) {
|
||||
$value |= ord($input[$i]) << 16;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 12) & 0x3f];
|
||||
if ($i++ >= $count) {
|
||||
break;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 18) & 0x3f];
|
||||
} while ($i < $count);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function gensaltPrivate($input, $options)
|
||||
{
|
||||
$output = '$P$';
|
||||
$output .= $this->itoa64[min($options['iteration_count_log2'] + ((PHP_VERSION >= '5') ? 5 : 3), 30)];
|
||||
$output .= $this->encode64($input, 6);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $password
|
||||
* @param String $setting
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function cryptPrivate($password, $setting)
|
||||
{
|
||||
$output = '*0';
|
||||
if (substr($setting, 0, 2) === $output) {
|
||||
$output = '*1';
|
||||
}
|
||||
$id = substr($setting, 0, 3);
|
||||
// We use "$P$", phpBB3 uses "$H$" for the same thing
|
||||
if ($id !== '$P$' && $id !== '$H$') {
|
||||
return $output;
|
||||
}
|
||||
$count_log2 = strpos($this->itoa64, $setting[3]);
|
||||
if ($count_log2 < 7 || $count_log2 > 30) {
|
||||
return $output;
|
||||
}
|
||||
$count = 1 << $count_log2;
|
||||
$salt = substr($setting, 4, 8);
|
||||
if (strlen($salt) !== 8) {
|
||||
return $output;
|
||||
}
|
||||
/**
|
||||
* We were kind of forced to use MD5 here since it's the only
|
||||
* cryptographic primitive that was available in all versions of PHP
|
||||
* in use. To implement our own low-level crypto in PHP
|
||||
* would have result in much worse performance and
|
||||
* consequently in lower iteration counts and hashes that are
|
||||
* quicker to crack (by non-PHP code).
|
||||
*/
|
||||
$hash = md5($salt . $password, true);
|
||||
do {
|
||||
$hash = md5($hash . $password, true);
|
||||
} while (--$count);
|
||||
$output = substr($setting, 0, 12);
|
||||
$output .= $this->encode64($hash, 16);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function gensaltBlowfish($input, $options)
|
||||
{
|
||||
/**
|
||||
* This one needs to use a different order of characters and a
|
||||
* different encoding scheme from the one in encode64() above.
|
||||
* We care because the last character in our encoded string will
|
||||
* only represent 2 bits. While two known implementations of
|
||||
* bcrypt will happily accept and correct a salt string which
|
||||
* has the 4 unused bits set to non-zero, we do not want to take
|
||||
* chances and we also do not want to waste an additional byte
|
||||
* of entropy.
|
||||
*/
|
||||
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
$output = '$2a$';
|
||||
$output .= chr(ord('0') + intval($options['iteration_count_log2'] / 10));
|
||||
$output .= chr(ord('0') + $options['iteration_count_log2'] % 10);
|
||||
$output .= '$';
|
||||
$i = 0;
|
||||
do {
|
||||
$c1 = ord($input[$i++]);
|
||||
$output .= $itoa64[$c1 >> 2];
|
||||
$c1 = ($c1 & 0x03) << 4;
|
||||
if ($i >= 16) {
|
||||
$output .= $itoa64[$c1];
|
||||
break;
|
||||
}
|
||||
$c2 = ord($input[$i++]);
|
||||
$c1 |= $c2 >> 4;
|
||||
$output .= $itoa64[$c1];
|
||||
$c1 = ($c2 & 0x0f) << 2;
|
||||
$c2 = ord($input[$i++]);
|
||||
$c1 |= $c2 >> 6;
|
||||
$output .= $itoa64[$c1];
|
||||
$output .= $itoa64[$c2 & 0x3f];
|
||||
} while (1);
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* Scrypt accepted options:
|
||||
* string? salt; auto-generated if empty
|
||||
* int costCpu
|
||||
* int costMemory
|
||||
* int costParallel
|
||||
* int length
|
||||
*
|
||||
* Reference: https://github.com/DomBlack/php-scrypt/blob/master/scrypt.php#L112-L116
|
||||
*/
|
||||
class Scrypt extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
$options = $this->getOptions();
|
||||
|
||||
return \scrypt($password, $options['salt'], $options['costCpu'], $options['costMemory'], $options['costParallel'], $options['length']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
return $hash === $this->hash($password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64 ];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* This is Scrypt hash with some additional steps added by Google.
|
||||
*
|
||||
* string salt
|
||||
* string saltSeparator
|
||||
* strin signerKey
|
||||
*
|
||||
* Reference: https://github.com/DomBlack/php-scrypt/blob/master/scrypt.php#L112-L116
|
||||
*/
|
||||
class Scryptmodified extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
$options = $this->getOptions();
|
||||
|
||||
$derivedKeyBytes = $this->generateDerivedKey($password);
|
||||
$signerKeyBytes = \base64_decode($options['signerKey']);
|
||||
|
||||
$hashedPassword = $this->hashKeys($signerKeyBytes, $derivedKeyBytes);
|
||||
|
||||
return \base64_encode($hashedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
return $this->hash($password) === $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ ];
|
||||
}
|
||||
|
||||
private function generateDerivedKey(string $password)
|
||||
{
|
||||
$options = $this->getOptions();
|
||||
|
||||
$saltBytes = \base64_decode($options['salt']);
|
||||
$saltSeparatorBytes = \base64_decode($options['saltSeparator']);
|
||||
|
||||
$password = mb_convert_encoding($password, 'UTF-8');
|
||||
$derivedKey = \scrypt($password, $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64);
|
||||
$derivedKey = \hex2bin($derivedKey);
|
||||
|
||||
return $derivedKey;
|
||||
}
|
||||
|
||||
private function hashKeys($signerKeyBytes, $derivedKeyBytes): string
|
||||
{
|
||||
$key = \substr($derivedKeyBytes, 0, 32);
|
||||
|
||||
$iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
|
||||
$hash = \openssl_encrypt($signerKeyBytes, 'aes-256-ctr', $key, OPENSSL_RAW_DATA, $iv);
|
||||
|
||||
return $hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\Hash;
|
||||
|
||||
use Appwrite\Auth\Hash;
|
||||
|
||||
/*
|
||||
* SHA accepted options:
|
||||
* string? version. Allowed:
|
||||
* - Version 1: sha1
|
||||
* - Version 2: sha224, sha256, sha384, sha512/224, sha512/256, sha512
|
||||
* - Version 3: sha3-224, sha3-256, sha3-384, sha3-512
|
||||
*
|
||||
* Reference: https://www.php.net/manual/en/function.hash-algos.php
|
||||
*/
|
||||
class Sha extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
{
|
||||
$algo = $this->getOptions()['version'];
|
||||
|
||||
return \hash($algo, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
return $this->hash($password) === $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default options for specific hashing algo
|
||||
*
|
||||
* @return array options named array
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'version' => 'sha3-512' ];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue