From 25f6255c226179d44eac0278ec2617d8cbad57ca Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 3 Sep 2025 09:12:48 +0700 Subject: [PATCH 1/8] Buat Dummy Pak Alam Testing --- app/Config/Routes.php | 5 + app/Controllers/NUHATEMP.php | 197 +++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 app/Controllers/NUHATEMP.php diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 1f0fecf..492f2d2 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -10,6 +10,11 @@ $routes->options('(:any)', function() { }); $routes->get('/', 'Home::index'); +$routes->get('/api/v1/emr/lab/list-new', 'NUHATEMP::index'); +$routes->post('/api/v1/emr/lab/insert', 'NUHATEMP::create'); +$routes->post('/api/v1/emr/lab/update-validasi', 'NUHATEMP::update'); +$routes->post('/api/v1/emr/lab/detail', 'NUHATEMP::detail'); + $routes->post('/auth/login/', 'Auth::login'); $routes->post('/auth/change_pass/', 'Auth::change_pass'); $routes->post('/auth/register/', 'Auth::register'); diff --git a/app/Controllers/NUHATEMP.php b/app/Controllers/NUHATEMP.php new file mode 100644 index 0000000..ccbddde --- /dev/null +++ b/app/Controllers/NUHATEMP.php @@ -0,0 +1,197 @@ +db = \Config\Database::connect(); + } + + // OK - Done + public function index() { + + $valid_from = $this->request->getVar('valid_from'); + $valid_to = $this->request->getVar('valid_to'); + try { + // Data pasien ditemukan dan mengembalikan - success 200 + return $this->respond([ + "response" => [ + "list" => [ + [ + "tgl" => "2023-07-31T00:12:00Z", + "no_lab" => 153304, + "no_rm" => "001063898", + "nama" => "WAHYUDI", + "tgl_lahir" => "1976-05-15T00:00:00Z", + "jenis_kelamin" => "Laki-laki", + "umur" => "47 tahun, 2 bulan, 15 hari", + "alamat" => "KP GEBANG RT 01/03 SANGIANG JAYA PERIUK", + "ruang" => "", + "kelas" => "", + "status" => "BPJS", + "dokter_pengirim" => "dr. Arie Asnafi, Sp.U", + "jenis_lab" => "pk", + "lis_id" => "2307310001", + "id_ruangan" => "1", + "nama_ruangan" => "Flamboyan", + "id_asuransi" => "2", + "nama_asuransi" => "BPJS KESEHATAN", + "cito" => false, + "list_test" => [ + [ + "detail_id" => 265833, + "no_lab" => 153304, + "test_id" => 72, + "nama_test" => "Glukosa Sewaktu", + "jenis_lab" => "pk", + "jenis_test" => "t", + "detail_test" => [] + ] + ] + ], + [ + "tgl" => "2023-07-31T00:53:00Z", + "no_lab" => 153307, + "no_rm" => "001301669", + "nama" => "RAFFASYAH ALKHALIFI PUTRA H", + "tgl_lahir" => "2017-11-28T00:00:00Z", + "jenis_kelamin" => "Laki-laki", + "umur" => "5 tahun, 8 bulan, 2 hari", + "alamat" => "JL TARUMANEGARA I / 4 RT 04 RW 022", + "ruang" => "", + "kelas" => "", + "status" => "BPJS", + "dokter_pengirim" => "dr. Arif Budiman, Sp.A (K)", + "jenis_lab" => "pk", + "lis_id" => "2307310004", + "id_ruangan" => "1", + "nama_ruangan" => "Flamboyan", + "id_asuransi" => "2", + "nama_asuransi" => "BPJS KESEHATAN", + "list_test" => [ + [ + "detail_id" => 265836, + "no_lab" => 153307, + "test_id" => 31, + "nama_test" => "Darah Lengkap", + "jenis_lab" => "pk", + "jenis_test" => "p", + "detail_test" => [ + ["paket_id"=>31,"index"=>1,"spasi"=>"0","test_id"=>16,"nama_test"=>"Hemoglobin"], + ["paket_id"=>31,"index"=>2,"spasi"=>"0","test_id"=>26,"nama_test"=>"Leukosit"], + ["paket_id"=>31,"index"=>3,"spasi"=>"0","test_id"=>28,"nama_test"=>"Eritrosit"], + ["paket_id"=>31,"index"=>4,"spasi"=>"0","test_id"=>29,"nama_test"=>"Hematokrit"], + ["paket_id"=>31,"index"=>5,"spasi"=>"0","test_id"=>30,"nama_test"=>"Trombosit"], + ["paket_id"=>31,"index"=>6,"spasi"=>"0","test_id"=>32,"nama_test"=>"Hitung Jenis"], + ["paket_id"=>31,"index"=>7,"spasi"=>"0","test_id"=>33,"nama_test"=>"Eosinofil"], + ["paket_id"=>31,"index"=>8,"spasi"=>"0","test_id"=>34,"nama_test"=>"Basofil"], + ["paket_id"=>31,"index"=>9,"spasi"=>"0","test_id"=>35,"nama_test"=>"Netrofil Batang"], + ["paket_id"=>31,"index"=>10,"spasi"=>"0","test_id"=>36,"nama_test"=>"Netrofil Segmen"], + ["paket_id"=>31,"index"=>11,"spasi"=>"0","test_id"=>37,"nama_test"=>"Limfosit"], + ["paket_id"=>31,"index"=>12,"spasi"=>"0","test_id"=>38,"nama_test"=>"Monosit"], + ["paket_id"=>31,"index"=>13,"spasi"=>"0","test_id"=>39,"nama_test"=>"Laju Endap Darah"] + ] + ] + ] + ] + ] + ], + "metadata" => [ + "message" => "Ok", + "code" => 200 + ] + ], 200); + + } catch (\Exception $e) { + // Error Server Mengembalikan 500 + return $this->failServerError('Something went wrong.'.$e->getMessage()); + } + } + + // OK - Done + public function create() { + try { + // Data pasien ditemukan dan mengembalikan - success 200 + return $this->respond([ + "message"=> "Ok", + 'status' => 200 + ], 200); + + } catch (\Exception $e) { + // Error Server Mengembalikan 500 + return $this->failServerError('Something went wrong.'.$e->getMessage()); + } + } + + // OK - Done + public function update() { + try { + // Data pasien ditemukan dan mengembalikan - success 200 + return $this->respond([ + "message"=> "Ok", + 'status' => 200 + ], 200); + + } catch (\Exception $e) { + // Error Server Mengembalikan 500 + return $this->failServerError('Something went wrong.'.$e->getMessage()); + } + } + + // OK - Done + public function detail() { + try { + // Data pasien ditemukan dan mengembalikan - success 200 + return $this->respond([ + "response" => [ + "tgl" => "2024-03-08T09:37:00Z", + "no_lab" => 3021, + "no_rm" => "000264395", + "nama" => "CANDY RAMADONA, AN", + "tgl_lahir" => "2007-09-02", + "jenis_kelamin" => "Perempuan", + "umur" => "2023 tahun, 2 bulan, 7 hari", + "alamat" => "PERUM PONDOK JAGUNG BLOK AC.45 001/004", + "ruang" => "", + "kelas" => "", + "status" => "ASURANSI SINAR MAS, PT", + "id_dokter_pengirim" => 2, + "dokter_pengirim" => "dr.Mila Agustia.Sp.A", + "jenis_lab" => "pk", + "lis_id" => "240308208", + "id_ruangan" => "1", + "nama_ruangan" => "DAMAR", + "id_asuransi" => "118", + "nama_asuransi" => "ASURANSI SINAR MAS, PT", + "cito" => false, + "list_test" => [ + [ + "detail_id" => 4981, + "no_lab" => 3021, + "test_id" => 145, + "nama_test" => "Urin Lengkap (Paket)", + "jenis_lab" => "", + "jenis_test" => "", + "detail_test" => null + ] + ] + ], + "metadata" => [ + "message" => "Ok", + "code" => 200 + ] + ], 200); + + } catch (\Exception $e) { + // Error Server Mengembalikan 500 + return $this->failServerError('Something went wrong.'.$e->getMessage()); + } + } + + +} \ No newline at end of file From 87097881140ba16b7b016463ab308fc8ae11dad7 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 3 Sep 2025 15:36:55 +0700 Subject: [PATCH 2/8] Update JWT for Auth --- app/Config/Routes.php | 9 ++- app/Controllers/Auth.php | 144 ++++++++++++++++++++++++++------------- app/Filters/Cors.php | 3 +- 3 files changed, 104 insertions(+), 52 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 492f2d2..8bef71b 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -10,14 +10,17 @@ $routes->options('(:any)', function() { }); $routes->get('/', 'Home::index'); +//PUNYA GUS INI TEMP $routes->get('/api/v1/emr/lab/list-new', 'NUHATEMP::index'); $routes->post('/api/v1/emr/lab/insert', 'NUHATEMP::create'); $routes->post('/api/v1/emr/lab/update-validasi', 'NUHATEMP::update'); $routes->post('/api/v1/emr/lab/detail', 'NUHATEMP::detail'); -$routes->post('/auth/login/', 'Auth::login'); -$routes->post('/auth/change_pass/', 'Auth::change_pass'); -$routes->post('/auth/register/', 'Auth::register'); +$routes->post('/api/auth/login/', 'Auth::login'); +$routes->post('/api/auth/change_pass/', 'Auth::change_pass'); +$routes->post('/api/auth/register/', 'Auth::register'); +$routes->get('/api/auth/check/', 'Auth::checkAuth'); +$routes->post('/api/auth/logout/', 'Auth::logout'); $routes->get('/api/patient', 'Patient::index'); $routes->post('/api/patient', 'Patient::create'); diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index ff41e0d..7f04e11 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -5,6 +5,7 @@ namespace App\Controllers; use CodeIgniter\API\ResponseTrait; use CodeIgniter\Controller; use \Firebase\JWT\JWT; +use CodeIgniter\Cookie\Cookie; class Auth extends Controller { use ResponseTrait; @@ -13,7 +14,52 @@ class Auth extends Controller { $this->db = \Config\Database::connect(); } + // public function login() { + // $username = $this->request->getVar('username'); + // $password = $this->request->getVar('password'); + // $key = getenv('JWT_SECRET'); + + // if (!$username) { + // return $this->fail('Username required.', 400); + // } + + // $sql = "SELECT * FROM users WHERE username=".$this->db->escape($username); + // $query = $this->db->query($sql); + // $row = $query->getRowArray(); + + // if (!$row) { + // return $this->fail('User not found.', 401); // Use 401 for authentication failures + // } + + // if (!password_verify($password, $row['password'])) { + // return $this->fail('Invalid password.', 401); + // } + + // // JWT payload + // $payload = [ + // 'userid' => $row['id'], + // 'username' => $row['username'], + // 'exp' => time() + 3600 + // ]; + + // try { + // $jwt = JWT::encode($payload, $key, 'HS256'); + // } catch (Exception $e) { + // return $this->fail('Error generating JWT: ' . $e->getMessage(), 500); + // } + + // // Update last_login + // //$this->userModel->update($user['id'], ['lastlogin' => date('Y-m-d H:i:s')]); + + // $response = [ + // 'status' => 'success', + // 'message' => 'Login successful', + // 'token' => $jwt, + // ]; + // return $this->respond($response); + // } public function login() { + $username = $this->request->getVar('username'); $password = $this->request->getVar('password'); $key = getenv('JWT_SECRET'); @@ -21,23 +67,24 @@ class Auth extends Controller { if (!$username) { return $this->fail('Username required.', 400); } - - $sql = "select * from users where username=".$this->db->escape($username); + + $sql = "SELECT * FROM users WHERE username=" . $this->db->escape($username); $query = $this->db->query($sql); $row = $query->getRowArray(); if (!$row) { - return $this->fail('User not found.', 401); // Use 401 for authentication failures + return $this->fail('User not found.', 401); } - + if (!password_verify($password, $row['password'])) { return $this->fail('Invalid password.', 401); } - + // JWT payload $payload = [ + 'userid' => $row['id'], 'username' => $row['username'], - 'exp' => time() + 3600 + 'exp' => time() + 3600 ]; try { @@ -46,14 +93,23 @@ class Auth extends Controller { return $this->fail('Error generating JWT: ' . $e->getMessage(), 500); } - // Update last_login - //$this->userModel->update($user['id'], ['lastlogin' => date('Y-m-d H:i:s')]); + // Set cookie (HttpOnly + Secure + SameSite=Strict) + $this->response->setCookie([ + 'name' => 'token', + 'value' => $jwt, + 'expire' => 3600, // 1 jam + 'path' => '/', + 'secure' => true, // set true kalau sudah HTTPS + 'httponly' => true, + 'samesite' => Cookie::SAMESITE_NONE // set true kalau sudah HTTPS + // 'samesite' => Cookie::SAMESITE_STRICT + ]); - $response = [ - 'message' => 'Login successful', - 'token' => $jwt, - ]; - return $this->respond($response); + // Response tanpa token di body + return $this->respond([ + 'status' => 'success', + 'message' => 'Login successful' + ]); } public function change_pass() { @@ -78,58 +134,50 @@ class Auth extends Controller { } public function register() { + $username = $this->request->getJsonVar('username'); $password = $this->request->getJsonVar('password'); $password = password_hash($password, PASSWORD_DEFAULT); - $master = $this->request->getJsonVar('master'); - $masterkey = getenv('MASTERKEY'); + // $master = $this->request->getJsonVar('master'); + // $masterkey = getenv('MASTERKEY'); + + // if($master != $masterkey) { + // return $this->fail('Invalid master key.', 401); + // } - if($master != $masterkey) { - return $this->fail('Invalid master key.', 401); - } - - $sql = "insert into users(username, password) values('$username', '$password')"; + $sql = "INSERT INTO users(username, password) values('$username', '$password')"; $this->db->query($sql); $response = [ - 'message' => "user $username created" + 'message' => "User $username created" ]; return $this->respondCreated($response); } public function checkAuth() { - $authorizationHeader = $this->request->getHeader('Authorization'); + $token = $this->request->getCookie('token'); + $key = getenv('JWT_SECRET'); - if (!$authorizationHeader) { - return $this->fail('Authorization header is missing', 401); + if (!$token) { + return $this->fail('No token found', 401); } - $authHeaderValue = $authorizationHeader->getValue(); - - if (empty($authHeaderValue)) { - return $this->fail('Authorization header is empty', 401); - } - - // Extract the token from the "Bearer " format - if (strpos($authHeaderValue, 'Bearer ') === 0) { - $token = substr($authHeaderValue, 7); - } else { - $token = $authHeaderValue; // Assume the header contains only the token - } - - try { - $decoded = JWT::decode($token, $this->key, ['HS256']); // Use the Key object - // You can now access user data from $decoded - $response = [ - 'message' => 'Authentication successful', - 'user' => $decoded, // return the decoded token - ]; - return $this->respond($response); - - } catch (Exception $e) { - return $this->fail('Invalid token: ' . $e->getMessage(), 401); + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return $this->respond([ + 'status' => 'success', + 'message' => 'Authenticated', + 'data' => $decoded + ]); + } catch (\Exception $e) { + return $this->fail('Invalid or expired token: ' . $e->getMessage(), 401); } } + public function logout() { + return $this->response + ->deleteCookie('token') + ->setJSON(['message' => 'Logout successful']); + } + } \ No newline at end of file diff --git a/app/Filters/Cors.php b/app/Filters/Cors.php index e989e43..c18b5aa 100644 --- a/app/Filters/Cors.php +++ b/app/Filters/Cors.php @@ -22,7 +22,8 @@ class Cors implements FilterInterface if (in_array($origin, $this->allowedOrigins)) { $response->setHeader('Access-Control-Allow-Origin', $origin); $response->setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS'); - $response->setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With'); + $response->setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, Accept, Origin, Cache-Control, Pragma'); + // $response->setHeader('Access-Control-Allow-Headers', '*'); $response->setHeader('Access-Control-Allow-Credentials', 'true'); } From 37816b8b7ba43e5ca115fc22bf7481ab523b9862 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 3 Sep 2025 22:45:57 +0700 Subject: [PATCH 3/8] Update JWT Success --- app/Config/Filters.php | 10 +- app/Config/Routes.php | 14 ++- app/Controllers/Auth.php | 234 ++++++++++++++++++++----------------- app/Filters/AuthFilter.php | 50 ++++++++ 4 files changed, 191 insertions(+), 117 deletions(-) create mode 100644 app/Filters/AuthFilter.php diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 9f335d2..19c87c6 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -35,6 +35,7 @@ class Filters extends BaseFilters 'forcehttps' => ForceHTTPS::class, 'pagecache' => PageCache::class, 'performance' => PerformanceMetrics::class, + 'auth' => \App\Filters\AuthFilter::class, ]; /** @@ -70,10 +71,11 @@ class Filters extends BaseFilters */ public array $globals = [ 'before' => [ - 'cors' - // 'honeypot', - // 'csrf', - // 'invalidchars', + // 'auth', + 'cors', + 'honeypot', + 'csrf', + 'invalidchars', ], 'after' => [ // 'honeypot', diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 8bef71b..a5f9802 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -16,11 +16,15 @@ $routes->post('/api/v1/emr/lab/insert', 'NUHATEMP::create'); $routes->post('/api/v1/emr/lab/update-validasi', 'NUHATEMP::update'); $routes->post('/api/v1/emr/lab/detail', 'NUHATEMP::detail'); -$routes->post('/api/auth/login/', 'Auth::login'); -$routes->post('/api/auth/change_pass/', 'Auth::change_pass'); -$routes->post('/api/auth/register/', 'Auth::register'); -$routes->get('/api/auth/check/', 'Auth::checkAuth'); -$routes->post('/api/auth/logout/', 'Auth::logout'); +// $routes->group('api', ['filter' => 'auth'], function($routes) { + $routes->post('/api/coba-auth', 'Auth::coba'); + + $routes->post('/api/auth/login', 'Auth::login'); + $routes->post('/api/auth/change_pass', 'Auth::change_pass'); + $routes->post('/api/auth/register', 'Auth::register'); + $routes->get('/api/auth/check', 'Auth::checkAuth'); + $routes->post('/api/auth/logout', 'Auth::logout'); +// }); $routes->get('/api/patient', 'Patient::index'); $routes->post('/api/patient', 'Patient::create'); diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index 7f04e11..1697704 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -4,62 +4,79 @@ namespace App\Controllers; use CodeIgniter\API\ResponseTrait; use CodeIgniter\Controller; -use \Firebase\JWT\JWT; + +use Firebase\JWT\JWT; +use Firebase\JWT\Key; +use Firebase\JWT\ExpiredException; +use Firebase\JWT\SignatureInvalidException; +use Firebase\JWT\BeforeValidException; use CodeIgniter\Cookie\Cookie; class Auth extends Controller { use ResponseTrait; + // ok public function __construct() { $this->db = \Config\Database::connect(); } - // public function login() { - // $username = $this->request->getVar('username'); - // $password = $this->request->getVar('password'); - // $key = getenv('JWT_SECRET'); + // ok + public function checkAuth() { + $token = $this->request->getCookie('token'); + $key = getenv('JWT_SECRET'); - // if (!$username) { - // return $this->fail('Username required.', 400); - // } - - // $sql = "SELECT * FROM users WHERE username=".$this->db->escape($username); - // $query = $this->db->query($sql); - // $row = $query->getRowArray(); + // Jika token FE tidak ada langsung kabarkan failed + if (!$token) { + return $this->respond([ + 'status' => 'failed', + 'message' => 'No token found' + ], 401); + } - // if (!$row) { - // return $this->fail('User not found.', 401); // Use 401 for authentication failures - // } - - // if (!password_verify($password, $row['password'])) { - // return $this->fail('Invalid password.', 401); - // } - - // // JWT payload - // $payload = [ - // 'userid' => $row['id'], - // 'username' => $row['username'], - // 'exp' => time() + 3600 - // ]; + try { + // Decode Token dengan Key yg ada di .env + $decodedPayload = JWT::decode($token, new Key($key, 'HS256')); - // try { - // $jwt = JWT::encode($payload, $key, 'HS256'); - // } catch (Exception $e) { - // return $this->fail('Error generating JWT: ' . $e->getMessage(), 500); - // } + return $this->respond([ + 'status' => 'success', + 'message' => 'Authenticated', + 'data' => $decodedPayload + ], 200); - // // Update last_login - // //$this->userModel->update($user['id'], ['lastlogin' => date('Y-m-d H:i:s')]); + } catch (ExpiredException $e) { + return $this->respond([ + 'status' => 'failed', + 'message' => 'Token expired', + 'data' => [] + ], 401); - // $response = [ - // 'status' => 'success', - // 'message' => 'Login successful', - // 'token' => $jwt, - // ]; - // return $this->respond($response); - // } + } catch (SignatureInvalidException $e) { + return $this->respond([ + 'status' => 'failed', + 'message' => 'Invalid token signature', + 'data' => [] + ], 401); + + } catch (BeforeValidException $e) { + return $this->respond([ + 'status' => 'failed', + 'message' => 'Token not valid yet', + 'data' => [] + ], 401); + + } catch (\Exception $e) { + return $this->respond([ + 'status' => 'failed', + 'message' => 'Invalid token: ' . $e->getMessage(), + 'data' => [] + ], 401); + } + } + + // ok public function login() { + // Ambil dari JSON Form dan Key .env $username = $this->request->getVar('username'); $password = $this->request->getVar('password'); $key = getenv('JWT_SECRET'); @@ -80,104 +97,105 @@ class Auth extends Controller { return $this->fail('Invalid password.', 401); } - // JWT payload + // Buat JWT payload $payload = [ 'userid' => $row['id'], 'username' => $row['username'], - 'exp' => time() + 3600 + 'exp' => time() + 86400 // 1 hari ]; try { + // Melakukan Hash terhadap Payload dengan Kunci .env menggunakan Algortima HMAC + SHA-256 $jwt = JWT::encode($payload, $key, 'HS256'); } catch (Exception $e) { return $this->fail('Error generating JWT: ' . $e->getMessage(), 500); } - // Set cookie (HttpOnly + Secure + SameSite=Strict) + // Kirim Respon ke HttpOnly yg akan disimpan di browser dan tidak akan dapat diakses oleh siapapun $this->response->setCookie([ - 'name' => 'token', - 'value' => $jwt, - 'expire' => 3600, // 1 jam - 'path' => '/', - 'secure' => true, // set true kalau sudah HTTPS - 'httponly' => true, - 'samesite' => Cookie::SAMESITE_NONE // set true kalau sudah HTTPS - // 'samesite' => Cookie::SAMESITE_STRICT + 'name' => 'token', // nama token + 'value' => $jwt, // value dari jwt yg sudah di hash + 'expire' => 86400, // 1 hari + 'path' => '/', // valid untuk semua path + 'secure' => true, // set true kalau sudah HTTPS + 'httponly' => true, // dipakai agar cookie berikut tidak dapat diakses oleh javascript + 'samesite' => Cookie::SAMESITE_NONE ]); // Response tanpa token di body return $this->respond([ 'status' => 'success', 'message' => 'Login successful' - ]); + ], 200); } - public function change_pass() { - $db = \Config\Database::connect(); - $username = $this->request->getJsonVar('username'); - $password = $this->request->getJsonVar('password'); - $password = password_hash($password, PASSWORD_DEFAULT); - - $master = $this->request->getJsonVar('master'); - $masterkey = getenv('masterkey'); + // ok + public function logout() { + // Definisikan ini pada cookies browser, harus sama dengan cookies login + return $this->response->setCookie([ + 'name' => 'token', + 'value' => '', + 'expire' => time() - 3600, + 'path' => '/', + 'secure' => true, + 'httponly' => true, + 'samesite' => Cookie::SAMESITE_NONE - if($master != $masterkey) { - return $this->fail('Invalid master key.', 401); - } - - $sql = "update users set password='$password' where username='$username'"; - $query = $db->query($sql); - $response = [ - 'message' => "Password Changed for $username" - ]; - return $this->respond($response); + ])->setJSON([ + 'status' => 'success', + 'message' => 'Logout successful' + ], 200); } + // ok public function register() { $username = $this->request->getJsonVar('username'); $password = $this->request->getJsonVar('password'); - $password = password_hash($password, PASSWORD_DEFAULT); - // $master = $this->request->getJsonVar('master'); - // $masterkey = getenv('MASTERKEY'); - - // if($master != $masterkey) { - // return $this->fail('Invalid master key.', 401); - // } - - $sql = "INSERT INTO users(username, password) values('$username', '$password')"; - $this->db->query($sql); - $response = [ - 'message' => "User $username created" - ]; - return $this->respondCreated($response); - } - - public function checkAuth() { - $token = $this->request->getCookie('token'); - $key = getenv('JWT_SECRET'); - - if (!$token) { - return $this->fail('No token found', 401); - } - - try { - $decoded = JWT::decode($token, new Key($key, 'HS256')); + // Validasi + if (empty($username) || empty($password)) { return $this->respond([ - 'status' => 'success', - 'message' => 'Authenticated', - 'data' => $decoded - ]); - } catch (\Exception $e) { - return $this->fail('Invalid or expired token: ' . $e->getMessage(), 401); + 'status' => 'failed', + 'message' => 'Username and password are required' + ], 400); // Gunakan 400 Bad Request } + + $password = password_hash($password, PASSWORD_DEFAULT); + $sql = "INSERT INTO users(username, password) values('$username', '$password')"; + + return $this->respond([ + 'status' => 'success', + 'message' => 'User '.$username.' created' + ], 201); } - public function logout() { - return $this->response - ->deleteCookie('token') - ->setJSON(['message' => 'Logout successful']); - } + // public function change_pass() { + // $db = \Config\Database::connect(); + // $username = $this->request->getJsonVar('username'); + // $password = $this->request->getJsonVar('password'); + // $password = password_hash($password, PASSWORD_DEFAULT); -} \ No newline at end of file + // $master = $this->request->getJsonVar('master'); + // $masterkey = getenv('masterkey'); + + // if($master != $masterkey) { + // return $this->fail('Invalid master key.', 401); + // } + + // $sql = "update users set password='$password' where username='$username'"; + // $query = $db->query($sql); + // $response = [ + // 'message' => "Password Changed for $username" + // ]; + // return $this->respond($response); + // } + + public function coba() { + return $this->respond([ + 'status' => 'success', + 'message' => 'Already Login' + ],200); + } + +} diff --git a/app/Filters/AuthFilter.php b/app/Filters/AuthFilter.php new file mode 100644 index 0000000..ad9d297 --- /dev/null +++ b/app/Filters/AuthFilter.php @@ -0,0 +1,50 @@ +getCookie('token'); // ambil dari cookie + + // Kalau tidak ada token + if (!$token) { + return Services::response() + ->setStatusCode(401) + ->setJSON([ + 'status' => 'failed', + 'message' => 'Unauthorized: Token not found' + ]); + } + + try { + // Decode JWT : jika error maka akan mentrigger catch + $decoded = JWT::decode($token, new Key($key, 'HS256')); + + // Kalau mau, bisa inject user info ke request + // $request->userData = $decoded; + + } catch (\Exception $e) { + return Services::response() + ->setStatusCode(401) + ->setJSON([ + 'status' => 'failed', + 'message' => 'Unauthorized: ' . $e->getMessage() + ]); + } + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + // Tidak perlu apa-apa + } +} From f688956ee60df9284316231672642c94ac37a9cf Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 3 Sep 2025 23:02:27 +0700 Subject: [PATCH 4/8] Update Auth Register --- app/Controllers/Auth.php | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index 1697704..3fbb4ba 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -162,12 +162,28 @@ class Auth extends Controller { } $password = password_hash($password, PASSWORD_DEFAULT); - $sql = "INSERT INTO users(username, password) values('$username', '$password')"; + $sql = "INSERT INTO users(username, password) VALUES(?, ?)"; + + try { + // Jalankan kueri dan binding data secara terpisah + $this->db->query($sql, [$username, $hashedPassword]); + + // Respon sukses jika kueri berhasil + return $this->respond([ + 'status' => 'success', + 'message' => 'User ' . $username . ' successfully created.' + ], 201); // Kode 201 Created sudah benar untuk resource baru + + } catch (\Exception $e) { + + // Tangani error lain-lain + return $this->respond([ + 'status' => 'error', + 'message' => 'Failed to create user. Please try again later.' + ], 500); // Kode 500 Internal Server Error untuk masalah di server + } + - return $this->respond([ - 'status' => 'success', - 'message' => 'User '.$username.' created' - ], 201); } // public function change_pass() { From fa024277c4bc7fdb127802ff40b10edc35c5cbbd Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 3 Sep 2025 23:05:06 +0700 Subject: [PATCH 5/8] Update Auth Register-perbaikan --- app/Controllers/Auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index 3fbb4ba..6b1547b 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -161,7 +161,7 @@ class Auth extends Controller { ], 400); // Gunakan 400 Bad Request } - $password = password_hash($password, PASSWORD_DEFAULT); + $hashedPassword = password_hash($password, PASSWORD_DEFAULT); $sql = "INSERT INTO users(username, password) VALUES(?, ?)"; try { @@ -175,7 +175,7 @@ class Auth extends Controller { ], 201); // Kode 201 Created sudah benar untuk resource baru } catch (\Exception $e) { - + // Tangani error lain-lain return $this->respond([ 'status' => 'error', From 2af6fb474f975f674c184f91d022b2caca215c94 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 3 Sep 2025 23:06:34 +0700 Subject: [PATCH 6/8] Mematikan Filter --- app/Config/Filters.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 19c87c6..fe57dcb 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -73,9 +73,9 @@ class Filters extends BaseFilters 'before' => [ // 'auth', 'cors', - 'honeypot', - 'csrf', - 'invalidchars', + // 'honeypot', + // 'csrf', + // 'invalidchars', ], 'after' => [ // 'honeypot', From 6ae72a6bb1202f05c0a621c0ce78e14d9f395fb8 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Thu, 4 Sep 2025 09:42:30 +0700 Subject: [PATCH 7/8] Testing JWT Untuk Routes tertentu --- app/Config/Filters.php | 2 +- app/Config/Routes.php | 8 ++++---- app/Controllers/Auth.php | 19 ++++++++++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index fe57dcb..5ee9cb1 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -71,7 +71,7 @@ class Filters extends BaseFilters */ public array $globals = [ 'before' => [ - // 'auth', + 'auth', 'cors', // 'honeypot', // 'csrf', diff --git a/app/Config/Routes.php b/app/Config/Routes.php index a5f9802..a779411 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -16,15 +16,15 @@ $routes->post('/api/v1/emr/lab/insert', 'NUHATEMP::create'); $routes->post('/api/v1/emr/lab/update-validasi', 'NUHATEMP::update'); $routes->post('/api/v1/emr/lab/detail', 'NUHATEMP::detail'); -// $routes->group('api', ['filter' => 'auth'], function($routes) { - $routes->post('/api/coba-auth', 'Auth::coba'); - +$routes->group('api', ['filter' => 'auth'], function($routes) { + $routes->get('coba-auth', 'Auth::coba'); +}); $routes->post('/api/auth/login', 'Auth::login'); $routes->post('/api/auth/change_pass', 'Auth::change_pass'); $routes->post('/api/auth/register', 'Auth::register'); $routes->get('/api/auth/check', 'Auth::checkAuth'); $routes->post('/api/auth/logout', 'Auth::logout'); -// }); + $routes->get('/api/patient', 'Patient::index'); $routes->post('/api/patient', 'Patient::create'); diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index 6b1547b..bede8b8 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -208,10 +208,23 @@ class Auth extends Controller { // } public function coba() { + + $token = $this->request->getCookie('token'); + $key = getenv('JWT_SECRET'); + + // Decode Token dengan Key yg ada di .env + $decodedPayload = JWT::decode($token, new Key($key, 'HS256')); + return $this->respond([ - 'status' => 'success', - 'message' => 'Already Login' - ],200); + 'status' => 'success', + 'message' => 'Authenticated', + 'data' => $decodedPayload + ], 200); + + // return $this->respond([ + // 'status' => 'success', + // 'message' => 'Already Login' + // ],200); } } From e11325ec9917431734c5315e88c366ee91356541 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Thu, 4 Sep 2025 09:46:30 +0700 Subject: [PATCH 8/8] Hapus Auth pada Filter --- app/Config/Filters.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 5ee9cb1..fdc2e9b 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -71,7 +71,6 @@ class Filters extends BaseFilters */ public array $globals = [ 'before' => [ - 'auth', 'cors', // 'honeypot', // 'csrf',