Skip to content

Commit

Permalink
fix security issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Xanonymous-GitHub committed Dec 4, 2021
1 parent 779d867 commit 64ca7a4
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 41 deletions.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
FROM python:alpine

ARG PORT=7777
ARG HOST='0.0.0.0'

ENV PORT=$PORT
ENV HOST=$HOST

COPY . /heyptt

WORKDIR /heyptt

RUN pip3 install -r ./requirements.txt --upgrade
RUN pip3 install -r ./requirements.txt --upgrade --no-cache-dir

EXPOSE $PORT

Expand Down
6 changes: 5 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from flask import Flask, request
import crawler as cra
from renderer import render
from flask_wtf.csrf import CSRFProtect
import os

app = Flask(__name__, static_folder='website', static_url_path='')
app.config['JSON_AS_ASCII'] = False

app.config['SECRET_KEY'] = os.urandom(24)
csrf = CSRFProtect(app)
csrf.init_app(app)

@app.route('/', methods=['GET'])
def give_html():
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ bs4
requests
flask
waitress
flask-wtf
2 changes: 1 addition & 1 deletion serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
import app
import os

serve(app.app, host='0.0.0.0', port=os.environ['PORT'])
serve(app.app, host=os.environ['HOST'], port=os.environ['PORT'])
2 changes: 1 addition & 1 deletion website/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ <h1 class="title-text"></h1>
alt
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAOZlWElmTU0AKgAAAAgABgESAAMAAAABAAEAAAEaAAUAAAABAAAAVgEbAAUAAAABAAAAXgExAAIAAAAiAAAAZgEyAAIAAAAUAAAAiIdpAAQAAAABAAAAnAAAAAAAAAeAAAAAAQAAB4AAAAABQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKFdpbmRvd3MpADIwMjA6MDQ6MDUgMDE6Mzg6NTkAAASQBAACAAAAFAAAANKgAQADAAAAAQABAACgAgAEAAAAAQAAACCgAwAEAAAAAQAAACAAAAAAMjAxOTowNjowMiAxNzowMDoxOQB3c7+/AAAACXBIWXMAASdHAAEnRwEEDsU+AAAK3GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8eG1wTU06SW5zdGFuY2VJRD54bXAuaWlkOjkzMTdkZDU1LWRmNjEtNDhjZi1iYjE0LWRlZTZkZGU3MTI3MzwveG1wTU06SW5zdGFuY2VJRD4KICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+YWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjJlNDM4ZmQzLWIzYjUtNTk0NS1iMmE3LTRkMzU2OGIxYWY2ZDwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD54bXAuZGlkOjhjYmZhMTVkLTA4ODgtMTI0Ni05YWFhLTNiNDYyMzUxNjY5NzwveG1wTU06T3JpZ2luYWxEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06SGlzdG9yeT4KICAgICAgICAgICAgPHJkZjpTZXE+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTktMDYtMDJUMTc6MDA6MTkrMDg6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6OGNiZmExNWQtMDg4OC0xMjQ2LTlhYWEtM2I0NjIzNTE2Njk3PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNyZWF0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgMjEuMSAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAyMC0wMy0wM1QwMDo0MTo0MyswODowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDo2MTIzMWY4Zi1hMDNhLTQ5NjEtOTIxNS0zMDNlOTA0ZTkyMzM8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgMjEuMSAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAyMC0wNC0wNVQwMTozODo1OSswODowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDo5MzE3ZGQ1NS1kZjYxLTQ4Y2YtYmIxNC1kZWU2ZGRlNzEyNzM8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAyMC0wNC0wNVQwMTozODo1OSswODowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKFdpbmRvd3MpPC94bXA6Q3JlYXRvclRvb2w+CiAgICAgICAgIDx4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"></span>N.P.C.
<span>
<a href="https://github.com/NPC-GO/hey-ptt" target="_blank">
<a href="https://github.com/NPC-GO/hey-ptt" target="_blank" rel="nofollow noreferrer noopener">
<svg aria-hidden="true" class="octicon octicon-mark-github v-align-middle" height="15px"
style="position: relative;fill: white"
width="16px">
Expand Down
85 changes: 48 additions & 37 deletions website/js/index.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
"use strict";

let currentBoard = getCookie("board") || "Gossiping";
let prevPage, boards;
let loadMoreButton = document.getElementById("load-more-button");
let loadingIcon = document.getElementById("loading-icon");
let loadingIconChildren = loadingIcon.children;
const loadMoreButton = document.getElementById("load-more-button");
const loadingIcon = document.getElementById("loading-icon");
const loadingIconChildren = loadingIcon.children;

const getRandomIntInclusive = (min, max) => {
const randomBuffer = new Uint32Array(1);
window.crypto.getRandomValues(randomBuffer);
const randomNumber = randomBuffer[0] / (0xffffffff + 1);
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(randomNumber * (max - min + 1)) + min;
};

(async function () {
loadMoreButton.addEventListener("click", async () => {
await showList(prevPage);
});

let articleContainer = document.getElementById("article-container");
const articleContainer = document.getElementById("article-container");

function close() {
articleContainer.style.display = "none";
}

let closeArticle = document.getElementById("close-article");
const closeArticle = document.getElementById("close-article");
closeArticle.addEventListener("click", close);
onclick = (e) => {
if (e.target === articleContainer) {
close();
}
};

let boardsSelectBox = document.getElementById("boards");
const boardsSelectBox = document.getElementById("boards");
boardsSelectBox.addEventListener("change", changeBoard);

let colorBars = document.querySelectorAll(".colorful-line");
const randomColor = () => Math.floor(Math.random() * 16777215).toString(16);
const colorBars = document.querySelectorAll(".colorful-line");
const randomColor = () => Math.floor(getRandomIntInclusive(0, 9999) * 1677.7215).toString(16);
colorBars.forEach((coloBar) => {
coloBar.style.background = "linear-gradient(to top right," + "#" + randomColor() + "," + "#" + randomColor() + ")";
});
Expand All @@ -37,7 +48,7 @@ let loadingIconChildren = loadingIcon.children;

function request(url, method, parameters, ...header) {
return new Promise(function (resolve, reject) {
let httpRequest = new XMLHttpRequest();
const httpRequest = new XMLHttpRequest();
if (method === "GET") {
if (parameters) {
url += ("?" + parameters || "");
Expand All @@ -60,7 +71,7 @@ function request(url, method, parameters, ...header) {
}

function getCookie(name) {
let cookieArr = document.cookie.split(";");
const cookieArr = document.cookie.split(";");
for (const i of cookieArr) {
let cookiePair = i.split("=");
if (name === cookiePair[0].trim()) {
Expand Down Expand Up @@ -93,13 +104,13 @@ async function getArticleTitle(articleId, board) {
}

async function getList(page, board) {
let list = await request("/api/articles", "GET", `page=${page || ""}&board=${board || currentBoard}`)
const list = await request("/api/articles", "GET", `page=${page || ""}&board=${board || currentBoard}`)
.catch((e) => errorHandler(e));
return [list["articles"] || [], list["prev"] || []];
}

async function getBoards() {
let boards = await request("/api/boards", "GET")
const boards = await request("/api/boards", "GET")
.catch((e) => errorHandler(e));
return boards["boards"] || {boards: "Gossiping"};
}
Expand All @@ -108,13 +119,13 @@ async function showBoardsSelectorOptions() {
leaveError();
loadingIcon.style.display = "flex";
boards = await getBoards();
let boardsSelectBox = document.getElementById("boards");
const boardsSelectBox = document.getElementById("boards");
boards.forEach(board => {
let option = document.createElement("option");
const option = document.createElement("option");
option.text = board;
boardsSelectBox.add(option);
});
let inferredBoardIndex = getCookie("board-index") || 0;
const inferredBoardIndex = getCookie("board-index") || 0;
if (boardsSelectBox[inferredBoardIndex] !== currentBoard) {
boardsSelectBox.selectedIndex = boards.findIndex(board => board === currentBoard);
} else {
Expand All @@ -124,7 +135,7 @@ async function showBoardsSelectorOptions() {
}

async function changeBoard() {
let listContainer = document.getElementById("list");
const listContainer = document.getElementById("list");
listContainer.innerHTML = "";
currentBoard = boards[this.selectedIndex];
await showList("", currentBoard);
Expand All @@ -140,14 +151,14 @@ async function showList(page, board) {
loadMoreButton.textContent = "載入中...";
let list;
[list, prevPage] = await getList(page, board);
let listContainer = document.getElementById("list");
let progressBar = document.getElementsByClassName("progress-bar")[0];
let partOfProgress = 100 / list.length;
const listContainer = document.getElementById("list");
const progressBar = document.getElementsByClassName("progress-bar")[0];
const partOfProgress = 100 / list.length;
let progressBarStatus = 0;
progressBar.parentNode.style.display = "flex";
progressBar.style.width = "0";
(await Promise.all(list.map(async (articleId) => {
let cardData = await getArticleTitle(articleId, board).catch(e => ({
const cardData = await getArticleTitle(articleId, board).catch(e => ({
title: "無法載入文章",
time: e,
author: "",
Expand All @@ -165,12 +176,12 @@ async function showList(page, board) {
};
}))).forEach(({time, author, title, id, disabled}) => {
if (!disabled) {
let card = document.createElement("div");
let cardInfo = document.createElement("div");
let cardTitle = document.createElement("p");
let cardAuthor = document.createElement("p");
let cardTime = document.createElement("p");
let hr = document.createElement("hr");
const card = document.createElement("div");
const cardInfo = document.createElement("div");
const cardTitle = document.createElement("p");
const cardAuthor = document.createElement("p");
const cardTime = document.createElement("p");
const hr = document.createElement("hr");
card.className += "article-card";
cardInfo.className += "article-card-info";
cardTitle.className += "article-card-title";
Expand Down Expand Up @@ -203,14 +214,14 @@ async function showList(page, board) {
async function showArticle(articleId, board) {
leaveError();
loadingIcon.style.display = "flex";
let article = await getArticleWithContent(articleId, board);
const article = await getArticleWithContent(articleId, board);
if (article === undefined) {
errorHandler("404");
return;
}
let titleText = document.getElementsByClassName("title-text")[0];
let articleText = document.getElementsByClassName("article")[0];
let colorfulLine = document.getElementById("article-color-line");
const titleText = document.getElementsByClassName("title-text")[0];
const articleText = document.getElementsByClassName("article")[0];
const colorfulLine = document.getElementById("article-color-line");
colorfulLine.style.display = "none";
titleText.innerText = "";
articleText.innerText = "";
Expand All @@ -219,21 +230,21 @@ async function showArticle(articleId, board) {
articleText.innerHTML = article["content"];
colorfulLine.style.display = "inherit"
}, 600);
let articleContainer = document.getElementById("article-container");
const articleContainer = document.getElementById("article-container");
articleContainer.style.display = "block";
loadingIcon.style.display = "none";
await loadImages();
}

async function loadImages() {
await new Promise(resolve => setTimeout(() => resolve(), 800));
let content = document.getElementById("main-content");
let richContents = content.getElementsByTagName("blockquote");
const content = document.getElementById("main-content");
const richContents = content.getElementsByTagName("blockquote");
for (const richContent of richContents) {
let id = richContent.getAttribute("data-id");
let clientId = "9328a3cd4a074e4";
let imgUrl = "https://api.imgur.com/3/image/" + id;
let response = await request(imgUrl, "GET", null, {
const id = richContent.getAttribute("data-id");
const clientId = "9328a3cd4a074e4";
const imgUrl = "https://api.imgur.com/3/image/" + id;
const response = await request(imgUrl, "GET", null, {
"Authorization": `Client-ID ${clientId}`
}).catch((e) => errorHandler(e)) || "";
if (response.data.link && response.data.type) {
Expand Down

0 comments on commit 64ca7a4

Please sign in to comment.