-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
542 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Ghink Universe - 404</title> | ||
<link rel="icon" href="https://cdn.ghink.net/image/ghink/favicon.ico" type="image/x-icon"> | ||
<style> | ||
body { | ||
background-color: #2F3242; | ||
} | ||
svg { | ||
position: absolute; | ||
top: 50%; | ||
left: 50%; | ||
margin-top: -250px; | ||
margin-left: -400px; | ||
} | ||
.message-box { | ||
height: 200px; | ||
width: 380px; | ||
position: absolute; | ||
top: 50%; | ||
left: 50%; | ||
margin-top: -100px; | ||
margin-left: 50px; | ||
color: #FFF; | ||
font-family: Roboto; | ||
font-weight: 300; | ||
} | ||
.message-box h1 { | ||
font-size: 60px; | ||
line-height: 46px; | ||
margin-bottom: 40px; | ||
} | ||
.buttons-con .action-link-wrap { | ||
margin-top: 40px; | ||
} | ||
.buttons-con .action-link-wrap a { | ||
background: #68c950; | ||
padding: 8px 25px; | ||
border-radius: 4px; | ||
color: #FFF; | ||
font-weight: bold; | ||
font-size: 14px; | ||
transition: all 0.3s linear; | ||
cursor: pointer; | ||
text-decoration: none; | ||
margin-right: 10px | ||
} | ||
.buttons-con .action-link-wrap a:hover { | ||
background: #5A5C6C; | ||
color: #fff; | ||
} | ||
|
||
#Polygon-1 , #Polygon-2 , #Polygon-3 , #Polygon-4 , #Polygon-4, #Polygon-5 { | ||
animation: float 1s infinite ease-in-out alternate; | ||
} | ||
#Polygon-2 { | ||
animation-delay: .2s; | ||
} | ||
#Polygon-3 { | ||
animation-delay: .4s; | ||
} | ||
#Polygon-4 { | ||
animation-delay: .6s; | ||
} | ||
#Polygon-5 { | ||
animation-delay: .8s; | ||
} | ||
|
||
@keyframes float { | ||
100% { | ||
transform: translateY(20px); | ||
} | ||
} | ||
@media (max-width: 450px) { | ||
svg { | ||
position: absolute; | ||
top: 50%; | ||
left: 50%; | ||
margin-top: -250px; | ||
margin-left: -190px; | ||
} | ||
.message-box { | ||
top: 50%; | ||
left: 50%; | ||
margin-top: -100px; | ||
margin-left: -190px; | ||
text-align: center; | ||
} | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<svg width="380px" height="500px" viewBox="0 0 837 1045" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"> | ||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> | ||
<path d="M353,9 L626.664028,170 L626.664028,487 L353,642 L79.3359724,487 L79.3359724,170 L353,9 Z" id="Polygon-1" stroke="#007FB2" stroke-width="6" sketch:type="MSShapeGroup"></path> | ||
<path d="M78.5,529 L147,569.186414 L147,648.311216 L78.5,687 L10,648.311216 L10,569.186414 L78.5,529 Z" id="Polygon-2" stroke="#EF4A5B" stroke-width="6" sketch:type="MSShapeGroup"></path> | ||
<path d="M773,186 L827,217.538705 L827,279.636651 L773,310 L719,279.636651 L719,217.538705 L773,186 Z" id="Polygon-3" stroke="#795D9C" stroke-width="6" sketch:type="MSShapeGroup"></path> | ||
<path d="M639,529 L773,607.846761 L773,763.091627 L639,839 L505,763.091627 L505,607.846761 L639,529 Z" id="Polygon-4" stroke="#F2773F" stroke-width="6" sketch:type="MSShapeGroup"></path> | ||
<path d="M281,801 L383,861.025276 L383,979.21169 L281,1037 L179,979.21169 L179,861.025276 L281,801 Z" id="Polygon-5" stroke="#36B455" stroke-width="6" sketch:type="MSShapeGroup"></path> | ||
</g> | ||
</svg> | ||
<div class="message-box"> | ||
<h1>404</h1> | ||
<p>Page not found 页面找不到了</p> | ||
<div class="buttons-con"> | ||
<div class="action-link-wrap"> | ||
<a onclick="history.back(-1)" class="link-button link-back-button">Go Back 返回</a> | ||
<a href="https://www.ghink.net" class="link-button">Go Home 返回主页</a> | ||
</div> | ||
</div> | ||
</div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"DEBUG": false, | ||
"DB": { | ||
"host": "localhost", | ||
"user": "root", | ||
"password": "root", | ||
"database": "short_link" | ||
}, | ||
"KEYS": [ | ||
"Example" | ||
], | ||
"LISTEN": [ | ||
"0.0.0.0", | ||
50002 | ||
] | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import time, random, json, threading | ||
import pymysql | ||
from flask import Flask, request, redirect | ||
|
||
with open("config.json", "r") as fb: | ||
config = json.loads(fb.read()) | ||
DB = config["DB"] | ||
KEYS = config["KEYS"] | ||
LISTEN = config["LISTEN"] | ||
DEBUG = config["DEBUG"] | ||
|
||
app = Flask("Ghink Short Link Service") | ||
db = pymysql.connect( | ||
host=DB["host"], | ||
user=DB["user"], | ||
password=DB["password"], | ||
database=DB["database"] | ||
) | ||
|
||
field_map = { | ||
'A': 0, 'a': 1, 'B': 2, 'b': 3, | ||
'C': 4, 'c': 5, 'D': 6, 'd': 7, | ||
'1': 8, 'E': 9, 'e': 10, 'F': 11, | ||
'f': 12, 'G': 13, 'g': 14, 'H': 15, | ||
'h': 16, '2': 17, 'I': 18, 'i': 19, | ||
'J': 20, 'j': 21, 'K': 22, 'k': 23, | ||
'L': 24, 'l': 25, '3': 26, 'M': 27, | ||
'm': 28, 'N': 29, 'n': 30, 'O': 31, | ||
'o': 32, 'P': 33, 'p': 34, '4': 35, | ||
'Q': 36, 'q': 37, 'R': 38, 'r': 39, | ||
'S': 40, 's': 41, 'T': 42, 't': 43, | ||
'5': 44, 'U': 45, 'u': 46, 'V': 47, | ||
'v': 48, 'W': 49, 'w': 50, 'X': 51, | ||
'x': 52, '6': 53, 'Y': 54, 'y': 55, | ||
'Z': 56, 'z': 57, '7': 58, '8': 59, | ||
'9': 60, '0': 61} | ||
|
||
|
||
@app.route("/", methods=["GET"]) | ||
def index(): | ||
with open("index.html", "r", encoding="utf-8") as fb: | ||
return fb.read() | ||
|
||
|
||
@app.route("/<string:link_id>", methods=["GET"]) | ||
def route(link_id: str): | ||
global db | ||
for char in link_id: | ||
if char not in tuple(field_map.keys()): | ||
return redirect("https://www.ghink.net") | ||
link_id_converted = 0 | ||
for i in range(len(link_id)): | ||
link_id_converted += field_map[link_id[::-1][i]] * 56 ** i | ||
|
||
try: | ||
db.ping() | ||
except pymysql.err.InterfaceError: | ||
db = pymysql.connect( | ||
host=DB["host"], | ||
user=DB["user"], | ||
password=DB["password"], | ||
database=DB["database"] | ||
) | ||
|
||
cursor = db.cursor() | ||
cursor.execute('SELECT link, validity FROM links WHERE id=%s', link_id_converted) | ||
db.commit() | ||
link = cursor.fetchone() | ||
if link is None or link[0] is None: | ||
with open("404.html", "r", encoding="utf-8") as fb: | ||
return fb.read(), 404 | ||
if link[1] is not None and link[1] < time.time(): | ||
remove_thread = threading.Thread(target=remove_link, args=(link_id_converted,)) | ||
remove_thread.start() | ||
with open("404.html", "r", encoding="utf-8") as fb: | ||
return fb.read(), 404 | ||
return redirect(link[0]) | ||
|
||
|
||
@app.route("/", methods=["POST"]) | ||
def add(): | ||
global db | ||
key = request.form.get("key") | ||
link = request.form.get("link") | ||
validity = request.form.get("validity") | ||
# Judge whether fields are empty | ||
if key == "" or link == "": | ||
return json.dumps({"ok": False, "message": "bad field(s)", "id": ""}) | ||
# No access | ||
if key not in KEYS: | ||
return json.dumps({"ok": False, "message": "forbidden", "id": ""}) | ||
# Check validity | ||
if validity: | ||
if validity.isdecimal() and int(validity) > time.time(): | ||
validity = int(validity) | ||
else: | ||
return json.dumps({"ok": False, "message": "bad field(s)", "id": ""}) | ||
else: | ||
validity = None | ||
|
||
# Random | ||
while True: | ||
link_id_random = ''.join(random.sample(tuple(field_map.keys()), 6)) | ||
link_id_converted = 0 | ||
for i in range(len(link_id_random)): | ||
link_id_converted += field_map[link_id_random[::-1][i]] * 56 ** i | ||
# Get Cursor | ||
try: | ||
db.ping() | ||
except pymysql.err.InterfaceError: | ||
db = pymysql.connect( | ||
host=DB["host"], | ||
user=DB["user"], | ||
password=DB["password"], | ||
database=DB["database"] | ||
) | ||
cursor = db.cursor() | ||
cursor.execute('SELECT link FROM links WHERE id=%s', link_id_converted) | ||
db.commit() | ||
link_selected = cursor.fetchone() | ||
if link_selected is None: | ||
break | ||
# Insert | ||
cursor.execute("INSERT INTO `links` VALUES (%s, %s, %s)", [link_id_converted, link, validity]) | ||
db.commit() | ||
|
||
return json.dumps({"ok": True, "message": "successful", "id": link_id_random}) | ||
|
||
|
||
@app.route("/", methods=["PATCH"]) | ||
def reload(): | ||
global config, DB, KEYS, LISTEN, DEBUG | ||
|
||
with open("config.json", "r") as fb: | ||
config = json.loads(fb.read()) | ||
DB = config["DB"] | ||
KEYS = config["KEYS"] | ||
LISTEN = config["LISTEN"] | ||
DEBUG = config["DEBUG"] | ||
|
||
return json.dumps({"ok": True, "message": "successful"}) | ||
|
||
|
||
def remove_link(id): | ||
global db | ||
# Get Cursor | ||
try: | ||
db.ping() | ||
except pymysql.err.InterfaceError: | ||
db = pymysql.connect( | ||
host=DB["host"], | ||
user=DB["user"], | ||
password=DB["password"], | ||
database=DB["database"] | ||
) | ||
cursor = db.cursor() | ||
cursor.execute('DELETE FROM links WHERE id=%s', id) | ||
db.commit() | ||
|
||
|
||
if __name__ == "__main__": | ||
app.run(LISTEN[0], LISTEN[1], DEBUG) | ||
db.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; | ||
START TRANSACTION; | ||
SET time_zone = "+00:00"; | ||
|
||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; | ||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; | ||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; | ||
/*!40101 SET NAMES utf8mb4 */; | ||
|
||
CREATE TABLE `links` ( | ||
`id` bigint(20) NOT NULL, | ||
`link` text NOT NULL, | ||
`validity` bigint(20) DEFAULT NULL | ||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | ||
|
||
ALTER TABLE `links` | ||
ADD PRIMARY KEY (`id`); | ||
COMMIT; | ||
|
||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; | ||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; | ||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; |