Exists()) { // Account already exists $account->Load(); if (password_verify($password, $account->password)) throw new UnauthenticatedException($account->id, 401); $session = new Session(account_id: $account->id); } else { // Create a new account $session = new Session(account_id: $account->Save()); } CORSHelper(); $token = $session->Save(); $session->Load(); return api_json([ "token" => $token, "auth_date" => $session->date_authenticated ]); } public static function getAccount($id): string { if (!signed_in(request())) { $usernames = explode(",", Hajeebtok::$Config->GetByDotKey("Service.FakeUsernames")); CORSHelper(); return api_json([ "id" => $id, "password" => "password1234", "username" => $usernames[rand(0, count($usernames) - 1)], "verified" => rand(1, 10) > 8, "bio" => "SIGN IN to see this EPIC content!!!", "followers" => rand(5, 38203), "following" => rand(5, 6243), "myself" => false, "links" => [], "socialCredit" => rand(-20223, 20223) ]); } if ($id === "myself") $id = get_token_id(request()); Logger::Debug($id); Logger::Debug("Getting account id ($id)."); $account = new Account(id: $id); $account->Load(); $followers = count(new Follow(followee_id: $id)->LoadMany()); $following = count(new Follow(follower_id: $id)->LoadMany()); try { $links = new Link(account_id: $id)->LoadMany(); } catch (Exception $e) { $links = []; } CORSHelper(); return api_json([ "id" => $id, "username" => $account->username, "verified" => $account->verified, "bio" => $account->bio, "followers" => $followers, "following" => $following, "myself" => $id == get_token_id(request()), "links" => $links, "socialCredit" => $account->social_credit ]); } public static function getVideos($id): string { if(!signed_in(request())) { $titles = explode(",", Hajeebtok::$Config->GetByDotKey("Service.FakeTitles")); $descriptions = explode(",", Hajeebtok::$Config->GetByDotKey("Service.FakeDescriptions")); $usernames = explode(",", Hajeebtok::$Config->GetByDotKey("Service.FakeUsernames")); $feed = []; for($i = 0; $i < rand(6, 20); $i++) { $feed[] = [ "id" => rand(1, 10), "title" => $titles[rand(0, count($titles) - 1)], "description" => $descriptions[rand(0, count($descriptions) - 1)], "likes" => rand(20000, 37020), "dislikes" => rand(2, 12343), "comments" => rand(2, 1029), "shares" => rand(2, 200000), "author" => [ "id" => rand(2, 59), "verified" => rand(1, 10) > 8, "username" => $usernames[rand(0, count($usernames) - 1)], ], ]; } CORSHelper(); return api_json($feed); } if ($id === "myself") $id = get_token_id(request()); $account = new Account(id: $id); $video_number = intval(input("video") ?? "0"); $data = Hajeebtok::$Database->Query("SELECT * FROM videos WHERE author_id = :author_id", ["author_id" => $account->id]); if (empty($data)) throw new VideoNotFoundException(0, 404); $videos = []; $valid_video = false; foreach ($data as $video) { if($video_number === 0) $valid_video = true; if($video["id"] === $video_number) $valid_video = true; if(!$valid_video) continue; $account = new Account($video["author_id"]); $account->Load(); $videos[] = ["id" => $video["id"], "title" => $video["title"], "description" => $video["description"], "likes" => $video["likes"], "dislikes" => $video["dislikes"], "comments" => Hajeebtok::$Database->Single("SELECT COUNT(*) FROM comments WHERE video_id = :id", ["id" => $video["id"]]), "shares" => Hajeebtok::$Database->Single("SELECT COUNT(*) FROM messages INNER JOIN videos ON messages.video_id = videos.id WHERE videos.id = :id", ["id" => $video["id"]]), "author" => [ "id" => $video["author_id"], "verified" => $account->verified, "username" => $account->username, ], ]; } CORSHelper(); return api_json($videos); } public static function getPicture($id): string { $signed_in = signed_in(request()); if ($id === "myself") $id = get_token_id(request()); if ($signed_in) { try { $account = new Account(id: $id); $account->Load(); $picture_path = APP_ROOT . "/usercontent/pictures/$account->picture_hash.png"; } catch (Exception $e) { $picture_path = APP_ROOT . "/usercontent/pictures/not_found.png"; } } else { // this is hardcoded because i dont care $picture_path = APP_ROOT . "/usercontent/pictures/premium_" . rand(1, 57) . ".png"; } $mimeTypes = new MimeTypes(); $picture_contents = file_get_contents($picture_path); $picture_size = filesize($picture_path); $mime = $mimeTypes->getMimeType(pathinfo($picture_path, PATHINFO_EXTENSION)); $response = response(); $response->header("Content-Type: $mime"); $response->header("Content-Length: $picture_size"); $response->header("Cache-Control: max-age=3600, public"); return $picture_contents; } public static function getAvailablePremiumProfilePictures(): string { $pictures = []; for ($i = 1; $i <= 47; $i++) { $pictures[] = $i; } CORSHelper(); return api_json($pictures); } public static function getPremiumProfilePicture($id): string { $picture_path = APP_ROOT . "/usercontent/pictures/premium_$id.png"; $mime_types = new MimeTypes(); $picture_contents = file_get_contents($picture_path); $picture_size = filesize($picture_path); $mime = $mime_types->getMimeType(pathinfo($picture_path, PATHINFO_EXTENSION)); $response = response(); $response->header("Content-Type: $mime"); $response->header("Content-Length: $picture_size"); $response->header("Cache-Control: max-age=3600, public"); return $picture_contents; } public static function updateAccount(): string { if (!signed_in(request())) throw new UnauthenticatedException(0, 401); $id = get_token_id(request()); $picture_hash = input("picture_hash"); $picture = request()->getInputHandler()->file("picture"); $bio = input("bio"); $valid_picture_hash_list = [ "default", "premium_1", "premium_2", "premium_3", "premium_4", "premium_5", "premium_6", "premium_7", "premium_8", "premium_9", "premium_10", "premium_11", "premium_12", "premium_13", "premium_14", "premium_15", "premium_16", "premium_17", "premium_18", "premium_19", "premium_20", "premium_21", "premium_22", "premium_23", "premium_24", "premium_25", "premium_26", "premium_27", "premium_28", "premium_29", "premium_30", "premium_31", "premium_32", "premium_33", "premium_34", "premium_35", "premium_36", "premium_37", "premium_38", "premium_39", "premium_40", "premium_41", "premium_42", "premium_43", "premium_44", "premium_45", "premium_46", "premium_47", "premium_48", "premium_49", "premium_50", "premium_51", "premium_52", "premium_53", "premium_54", "premium_55", "premium_56", "premium_57" ]; if (empty($picture) && !empty($picture_hash)) { if (!in_array($picture_hash, $valid_picture_hash_list)) throw new SecurityFaultException("Attempt to path trace on /update endpoint.", 400); } else if (!empty($picture) && empty($picture_hash)) { $picture_hash = hash("sha256", $picture); $picture_path = APP_ROOT . "/usercontent/pictures/$picture_hash.png"; $size = getimagesize($picture); $crop = min($size[0], $size[1]); $image_contents = file_get_contents($picture); $image_string = imagecreatefromstring($image_contents); $cropped_image = imagecrop($image_string, [ "x" => 0, "y" => 0, "width" => $crop, "height" => $crop ]); imagepng($cropped_image, $picture_path); // save image and crop and turn into png (i love php) } else if (!empty($picture) && !empty($picture_hash)) { throw new InvalidRequestException(400); } $old_account = new Account(id: $id); $old_account->Load(); $new_account = new Account( id: $id, username: $old_account->username, password: $old_account->password, picture_hash: $picture_hash ?? $old_account->picture_hash, verified: $old_account->verified, bio: $bio ?? $old_account->bio, ); CORSHelper(); $new_account->Update(); return api_json([ "id" => $new_account->id, "username" => $new_account->username, "pictureHash" => in_array($new_account->picture_hash, $valid_picture_hash_list) ? $new_account->picture_hash : null, "bio" => $new_account->bio, "verified" => $new_account->verified, ]); } public static function addLink(): string { if (!signed_in(request())) throw new UnauthenticatedException(0, 401); $account_id = get_token_id(request()); $link = input("link"); $link_type = input("linkType"); $link_enum_type = LinkEnum::tryFrom($link_type); // todo: add enum type filtering $link = new Link(account_id: $account_id, type: $link_enum_type, url: $link); $link->Save(); return api_json([ "id" => $link->id, "url" => $link->url, "type" => $link->type->value, "account_id" => $link->account_id ]); } public static function getFollowers($id): string { if ($id === "myself") $id = get_token_id(request()); $followers = new Follow(followee_id: $id)->LoadMany(); if (empty($followers)) throw new FollowNotFoundException(0, 404); for ($i = 0; $i < count($followers); $i++) { $follower = $followers[$i]["follower_id"]; $account = new Account(id: $follower); $account->Load(); $followers[$i] = [ "followee_id" => (int)$id, "follower_id" => $follower, "username" => $account->username, "verified" => $account->verified ]; } return api_json($followers); } public static function getFollowing($id): string { if ($id === "myself") $id = get_token_id(request()); $following = new Follow(follower_id: $id)->LoadMany(); if (empty($following)) throw new FollowNotFoundException(0, 404); for ($i = 0; $i < count($following); $i++) { $followee = $following[$i]["followee_id"]; $account = new Account(id: $followee); $account->Load(); $following[$i] = [ "followee_id" => $followee, "follower_id" => (int)$id, "username" => $account->username, "verified" => $account->verified ]; } return api_json($following); } public static function search(): string { $signed_in = signed_in(request()); if(!$signed_in) { $data = []; $usernames = explode(",", Hajeebtok::$Config->GetByDotKey("Service.FakeUsernames")); for($i = 0; $i < rand(1, 13); $i++) { $data[] = [ "id" => rand(2, 10232), "username" => $usernames[rand(0, count($usernames) - 1)], "socialCredit" => rand(-2032, 1209312), "following" => rand(0, 10232), "followers" => rand(0, 10232), "bio" => "SIGN IN to see this EPIC content!!", "verified" => rand(1, 10) > 8, ]; } CORSHelper(); return api_json($data); } $query = input("query"); $account = new Account(username: $query); $data = $account->LoadMany(); $accounts = []; foreach($data as $account) { $followers = count(new Follow(followee_id: $account["id"])->LoadMany()); $following = count(new Follow(follower_id: $account["id"])->LoadMany()); $accounts[] = [ "id" => $account["id"], "username" => $account["username"], "socialCredit" => $account["social_credit"], "following" => $following, "followers" => $followers, "bio" => $account["bio"], "verified" => $account["verified"] === 1, ]; } CORSHelper(); return api_json($accounts); } public static function RegisterRoutes(): void { SimpleRouter::group([ "prefix" => "/account/", ], function () { SimpleRouter::get("/availablePremiumProfilePictures", [AccountController::class, "getAvailablePremiumProfilePictures"]); SimpleRouter::get("/getPremiumProfilePicture/{id}", [AccountController::class, "getPremiumProfilePicture"]); SimpleRouter::get("/{id}/get", [AccountController::class, "getAccount"]); SimpleRouter::get("/{id}/videos", [AccountController::class, "getVideos"]); SimpleRouter::get("/{id}/picture", [AccountController::class, "getPicture"]); //SimpleRouter::get("/{id}/followers", [AccountController::class, "getFollowers"]); //SimpleRouter::get("/{id}/following", [AccountController::class, "getFollowing"]); SimpleRouter::post("/token", [AccountController::class, "getToken"]); SimpleRouter::post("/update", [AccountController::class, "updateAccount"]); SimpleRouter::post("/addLink", [AccountController::class, "addLink"]); SimpleRouter::post("/search", [AccountController::class, "search"]); SimpleRouter::options("/update", "CORSHelper"); SimpleRouter::options("/token", "CORSHelper"); SimpleRouter::options("/{id}/get", "CORSHelper"); SimpleRouter::options("/{id}/videos", "CORSHelper"); SimpleRouter::options("/update", "CORSHelper"); SimpleRouter::options("/availablePremiumProfilePictures", "CORSHelper"); SimpleRouter::options("/getPremiumProfilePicture/{id}","CORSHelper"); SimpleRouter::options("/search", "CORSHelper"); }); } }