From dc6d5767bb9b6cfbe1e526630828a2099fdbbaa2 Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Wed, 24 May 2023 11:27:44 +0300 Subject: [PATCH] individual level pages!!!!!!!!! --- public/assets/icons/gd/download.png | Bin 0 -> 5380 bytes public/assets/icons/gd/like.png | Bin 0 -> 5870 bytes public/template/account_management.ecr | 2 +- public/template/index.ecr | 2 +- public/template/level.ecr | 258 +++++++++++++++++++++++++ public/template/levels.ecr | 9 +- src/endpoints/levels/uploadLevel.cr | 32 ++- src/template_endpoints/levels.cr | 23 ++- 8 files changed, 303 insertions(+), 23 deletions(-) create mode 100644 public/assets/icons/gd/download.png create mode 100644 public/assets/icons/gd/like.png create mode 100644 public/template/level.ecr diff --git a/public/assets/icons/gd/download.png b/public/assets/icons/gd/download.png new file mode 100644 index 0000000000000000000000000000000000000000..802ccefbf91ba5d93f67d5a3dafef84e01feef21 GIT binary patch literal 5380 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 z zcODl;(Qr33f4{nhw?!K#eNtJCrs=)*`g47Op!L1-Asx;pht957!I2jjB)v#frxP#;>A?{_%~~cClBMAck3+h{VNwsV)yfqN;6aXTU3? zdBvM6VOrMUovOft+FM>{VR7C*DS5+rcgfdY&_kh=)F6mfMqC;(nu6mZF5QHaRZdb? zbcg8u$rAMnE4@rF?^*4t0fCMP#ZzCVPjZTby>ceo6_ZH{hZ&n!3S6ibq#5D1#G5(( zVXV!K^(J32XUvFa2DZ4PW4N}~O5VovV*C29M*UiUp2R9pTq0WF@CT*Lp!kIr0~fxM zUc8Yj_JWYR|8lv(0UhOLjS-n5k`JLPHgTGyWKF|v3iDH0dJB4|TpU`3aml1%d#>i{ zj|~5=hNVjBgz-7smlTz`GlJZ3Uua0B1jAW52iYQaUT=Bm2+kgO3|;033V=wCwiozQ z6#N6yMb0Zg&=YQcrmodBBvVBx1iO)xEc-xQ zc!+{y!(_c=8*}w$;ZW)f1!i{lK#~NvLJ*>OuLqYk_!<)x~i|@q2EBv+P$g_(RL-N^ixzG1HKpFhrY!w$d?NTdego513xh!DSggnoytQ zZR2%~`|O~bCN!hT*XTMld4g!B=sxdWbzD^wr94jO*5y8i73g}y|KR@i6pHq(q(0~_ zM~nNR#1Zt0oQjUjbaYUZ4Nw0qyDv2-r?`pV^(p+Rmw6>DAtB+_!`{ZEzQkKx3jaPD zaf%TB`Ylm31M7#2rZ@Tu^5Wk_d_5Y4XDG4y*FT>bEH2`z72LGRbCQk>tNg&-Ipymg z*e&@?zc%4o88}B7pS|;Ao$(#%d^P#Fyq_~tisB9Y#QEL~2{&Dc1S@;P_Q?&8@J=p< z-K?Lb62t30mUdo?yc1Tn7lYZ#OKx?>PWbTNYIE0a{3&}A0vTB=m_wYiVz(eSk8a%l zpbA=9MiC210#3h``p)TH?VwnWfpX_hwG7HBf$biyMzuma44-7guL9AGe`DVx=2Um7 zg#;tLT6dc_-3+qMS9^oEfa6~SukK+`8@V41(C(PWNU$2*G>~o;7|i`;O(N0G?BK|% zo1g2$vPS}kV_Sv?!$O;R6FFbYuJd)@($agzkwhK7|5r$oPAtd%7PCJ`QO-IEk7@Is z20^>r<(}EC{F_Sri?$#uR6pZhXBr&BdX9CvIHOFK|o`??FjXg z#p(nT^9kDD@A0yH^nn8OBr;mG6i@gtL!}B6$rxJFzPsBq>FvEQO0|D3e&()keA>!p z45y7~LE|TJQu*h*>A#_#4+07M_chCcCrfp=B@YZ# zul{{=DLH!J;`i*h3OT6qn)K>$C@SetFvYmr?u<9x8ywT^pbon6yBQT+bfLOl8WoH^ z>R3WQ;R=Ad9$ucp{cG%$SL)n%^8Vu8OLV+G?}!UTDyyRm5?qe8_-_HNB&RN0Eo~n1 EKP>n0(f|Me literal 0 HcmV?d00001 diff --git a/public/template/account_management.ecr b/public/template/account_management.ecr index 82d1cb2..89eedaf 100644 --- a/public/template/account_management.ecr +++ b/public/template/account_management.ecr @@ -128,7 +128,7 @@ - "> + "> <%= File.read("public/assets/icons/bell.svg") %> diff --git a/public/template/index.ecr b/public/template/index.ecr index cf0a0ac..0c56a70 100644 --- a/public/template/index.ecr +++ b/public/template/index.ecr @@ -38,7 +38,7 @@
  • The Git repository
  • Account stuff
  • Song reuploading and searching
  • -
  • Levels and level reuploading
  • +
  • Levels and level reuploading
  • <%- if config_get("sessions.allow").as(Bool | Nil) -%>
  • The session creation page (for accessing features in 1.9)
  • <%- end -%> diff --git a/public/template/level.ecr b/public/template/level.ecr new file mode 100644 index 0000000..ec2d343 --- /dev/null +++ b/public/template/level.ecr @@ -0,0 +1,258 @@ + + + + + + + + <%= name %> by <%= username %> + + + + +
    + +
    +
    + <%= + difficulty = (difficulty_set || difficulty_community).try { |n| LevelDifficulty.new(n) } + demon_difficulty = demon_difficulty_int.try { |n| DemonDifficulty.new(n) } + "" + %> + <%- if stars -%> +
    + <%= stars %> +
    + <%- end -%> +
    +
    +
    +
    + <%= name %> +
    +
    + <%= downloads %> downloads <%= likes %> likes +
    +
    + +
    +
    + +
    +
    DESCRIPTION
    +
    + <%= description != "" ? HTML.escape(description) : "No description provided" %> +
    +
    + +
    +
    SONG
    +
    + <%- if song_name -%> + + + <%- if song_author && song_author != "" -%> + + <%- else -%> +
    unknown artist
    + <%- end -%> + <%- else -%> + idk + <%- end -%> +
    +
    + + + + + + <% + rank = 0 + scores.each do |percent, coins, username, icon_type, color1, color2, cube, ship, ball, ufo, wave, robot, spider, special, set_at| + rank = rank + 1 + + icon_value = [cube, ship, ball, ufo, wave, robot, spider][icon_type] + type_str = ["cube", "ship", "ball", "ufo", "wave", "robot", "spider"][icon_type] + + set_at_date = Time.parse(set_at, Format::TIME_FORMAT, Time::Location::UTC) + %> + + + + + + + + + <%- end -%> + <%- if scores.size == 0 -%> + + + + <%- end -%> +
    RANK + PERCENT + COINS + + PLAYER + TIME +
    #<%= rank %><%= percent %>% + " class="player-icon"> + + <%= username %> + + +
    + No scores +
    + +

    comments go here etc etc

    + + + diff --git a/public/template/levels.ecr b/public/template/levels.ecr index a433090..beae059 100644 --- a/public/template/levels.ecr +++ b/public/template/levels.ecr @@ -55,7 +55,10 @@ display: flex; flex-direction: column; align-items: center; - gap: 1em + gap: 1em; + } + .level a { + text-decoration: none; } @@ -69,8 +72,8 @@ "" %>
    - <%= name %>#<%= id %> - by <%= username %>
    + <%= name %>#<%= id %> + by <%= username %>
    <%- end -%> diff --git a/src/endpoints/levels/uploadLevel.cr b/src/endpoints/levels/uploadLevel.cr index 4ad72e7..31ac167 100644 --- a/src/endpoints/levels/uploadLevel.cr +++ b/src/endpoints/levels/uploadLevel.cr @@ -64,18 +64,16 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C LOG.debug { "allowed objects: #{allowed_objects.inspect}" } if forbidden_obj = level_objects.find do |obj| - if !obj.has_key?("1") - false - end - - id = obj["1"].to_i - if allowed_objects.size > 0 - if !allowed_objects.includes?(id) - true - end - else - if forbidden_objects.includes?(id) - true + if obj.has_key?("1") + id = obj["1"].to_i + if allowed_objects.size > 0 + if !allowed_objects.includes?(id) + true + end + else + if forbidden_objects.includes?(id) + true + end end end end @@ -83,12 +81,12 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C return "-1" end - if exploit_obj = level_objects.find do |obj| + if exploit_obj = level_objects.find { |obj| # target color ID - (obj.has_key?("23") && obj["23"].to_i < 0 || obj["23"].to_i > 1100) || + (obj.has_key?("23") && (obj["23"].to_i < 0 || obj["23"].to_i > 1100)) || # target group ID - (obj.has_key?("51") && obj["51"].to_i < 0 || obj["51"].to_i > 1100) - end + (obj.has_key?("51") && (obj["51"].to_i < 0 || obj["51"].to_i > 1100)) + } LOG.info { "preventing upload of level attempting to exploit invalid color/group IDs" } return "-1" end @@ -147,7 +145,7 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C # create new level next_id = IDs.get_next_id("levels") - DATABASE.exec("insert into levels (id, name, user_id, description, original, game_version, binary_version, password, requested_stars, unlisted, version, extra_data, level_info, editor_time, editor_time_copies, song_id, length, objects, coins, has_ldm, two_player) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", next_id, Clean.clean_special(params["levelName"])[..20-1], user_id, description[..140-1], params["original"].to_i, params["gameVersion"].to_i, (params["binaryVersion"]? || "0").to_i, params["password"] == "0" ? nil : params["password"].to_i, requested_stars, (params["unlisted"]? || "0").to_i == 1, params["levelVersion"].to_i, Clean.clean_special(extraString), Clean.clean_b64(params["levelInfo"]? || ""), (params["wt"]? || "0").to_i, (params["wt2"]? || "0").to_i, song_id.to_i, level_length, objects, coins, (params["ldm"]? || "0").to_i == 1, two_player) + DATABASE.exec("insert into levels (id, name, user_id, description, original, game_version, binary_version, password, requested_stars, unlisted, version, extra_data, level_info, editor_time, editor_time_copies, song_id, length, objects, coins, has_ldm, two_player) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", next_id, Clean.clean_basic(params["levelName"])[..20-1], user_id, description[..140-1], params["original"].to_i, params["gameVersion"].to_i, (params["binaryVersion"]? || "0").to_i, params["password"] == "0" ? nil : params["password"].to_i, requested_stars, (params["unlisted"]? || "0").to_i == 1, params["levelVersion"].to_i, Clean.clean_special(extraString), Clean.clean_b64(params["levelInfo"]? || ""), (params["wt"]? || "0").to_i, (params["wt2"]? || "0").to_i, song_id.to_i, level_length, objects, coins, (params["ldm"]? || "0").to_i == 1, two_player) File.write(DATA_FOLDER / "levels" / "#{next_id.to_s}.lvl", Base64.decode(params["levelString"])) diff --git a/src/template_endpoints/levels.cr b/src/template_endpoints/levels.cr index 40913b8..52d7e62 100644 --- a/src/template_endpoints/levels.cr +++ b/src/template_endpoints/levels.cr @@ -6,7 +6,7 @@ levels_per_page = 10 CrystalGauntlet.template_endpoints[{ name: "list_levels", - path: "/tools/levels", + path: "/levels", methods: ["get"] }] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) { context.response.content_type = "text/html" @@ -15,3 +15,24 @@ CrystalGauntlet.template_endpoints[{ levels = DATABASE.query_all("select levels.id, name, users.username, levels.community_difficulty, levels.difficulty, levels.demon_difficulty, levels.featured, levels.epic from levels left join users on levels.user_id = users.id order by levels.id desc limit #{levels_per_page} offset #{page * levels_per_page}", as: {Int32, String, String, Int32?, Int32?, Int32?, Bool, Bool}) ECR.embed("./public/template/levels.ecr", context.response) } + +CrystalGauntlet.template_endpoints[{ + name: "level_page", + path: "/levels/{id<\\d+>}", + methods: ["get"] +}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) { + context.response.content_type = "text/html" + id = params["id"].as(String).to_i + + begin + name, username, difficulty_community, difficulty_set, demon_difficulty_int, featured, epic, downloads, likes, stars, description, song_id, song_name, song_author, song_url, song_author_url = DATABASE.query_one("select levels.name, users.username, community_difficulty, difficulty, demon_difficulty, featured, epic, downloads, likes, levels.stars, description, song_id, song_data.name, song_authors.name, songs.url, song_authors.source from levels left join users on levels.user_id = users.id left join songs on songs.id = levels.song_id left join song_data on song_data.id = levels.song_id left join song_authors on song_data.author_id = song_authors.id where levels.id = ?", id, as: {String, String, Int32?, Int32?, Int32?, Bool, Bool, Int32, Int32, Int32?, String, Int32, String?, String?, String?, String?}) + rescue err + LOG.error {"whar.... #{err}"} + context.response.status = HTTP::Status::NOT_FOUND + return + end + + scores = DATABASE.query_all("select distinct percent, level_scores.coins, users.username, users.icon_type, users.color1, users.color2, users.cube, users.ship, users.ball, users.ufo, users.wave, users.robot, users.spider, users.special, set_at from level_scores join users on level_scores.account_id = users.account_id where level_id = ? order by percent desc, level_scores.coins desc, set_at limit 25", id, as: {Int32, Int32, String, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, String}) + + ECR.embed("./public/template/level.ecr", context.response) +}