Merge branch 'hax-wirechan-improvement'
accepted, thanks! :3
This commit is contained in:
commit
f9a0017dfe
5 changed files with 85 additions and 54 deletions
78
README.md
78
README.md
|
|
@ -1,47 +1,57 @@
|
||||||
# wirechan
|
# WireChan - Anonymous ImageBoard
|
||||||
|
|
||||||
imageboard written in python(flask)
|
## Description
|
||||||
|
WireChan is an anonymous imageboard built using the Flask framework and MongoDB as its database. It allows users to communicate on various topics without the risk of being identified, offering both anonymous and logged-in posting options.
|
||||||
|
|
||||||
# overview
|
### Features
|
||||||
|
- Anonymous and logged-in posting
|
||||||
|
- Admin dashboard for moderation
|
||||||
|
- Minimal dependencies
|
||||||
|
- Minimalistic design
|
||||||
|
|
||||||
wirechan is an anonymous(optional registration) imageboard written in Flask framework using MongoDB as a database. It's designed to be used
|
## Installation Instructions
|
||||||
as a way of communication for various topics without the fear of being recogniszed, if the user wishes to remain unknown.
|
|
||||||
|
|
||||||
# features
|
|
||||||
|
|
||||||
>Both logged-in and anonymous posting
|
|
||||||
|
|
||||||
>Admin dashboard for moderation
|
|
||||||
|
|
||||||
>No Javascript whatsoever
|
|
||||||
|
|
||||||
>Minimal dependencies
|
|
||||||
|
|
||||||
>Minimalistic design
|
|
||||||
|
|
||||||
# installation
|
|
||||||
|
|
||||||
1. Clone the repository:
|
1. Clone the repository:
|
||||||
```
|
|
||||||
|
```bash
|
||||||
git clone https://git.lainlounge.xyz/hornet/wirechan
|
git clone https://git.lainlounge.xyz/hornet/wirechan
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Create and activate virtual environment:
|
Create a virtual environment using venv:
|
||||||
```
|
|
||||||
python3 -m venv venv && source venv/bin/activate
|
```bash
|
||||||
|
python3 -m venv env
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Install the dependencies:
|
## Install the required dependencies:
|
||||||
```
|
|
||||||
python3 -m pip install -r requirements.txt
|
```bash
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Initialize the MongoDB server:
|
## Initialize MongoDB
|
||||||
```
|
|
||||||
mongo #or systemctl enable mongod && systemctl start mongod
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Start the server
|
Start MongoDB by creating a new database via the MongoDB shell.
|
||||||
```
|
Ensure the mongod service is running (for Windows, use mongo).
|
||||||
python3 app.py
|
Start the Flask application in development mode:
|
||||||
```
|
|
||||||
|
```bash
|
||||||
|
flask run
|
||||||
|
```
|
||||||
|
Open your browser to view the created page at the specified URL.
|
||||||
|
|
||||||
|
## How To Use
|
||||||
|
|
||||||
|
Log in to your Dashboard instance with valid credentials at http://localhost:5000.
|
||||||
|
Create a new post by clicking the "Add a new post" button.
|
||||||
|
View or manage your posts by logging out and creating a new account if needed.
|
||||||
|
|
||||||
|
## Additional Features
|
||||||
|
|
||||||
|
Admin Dashboard: View profiles, posts, history, and moderation statuses.
|
||||||
|
Minimal Dependencies: Built-in Flask and MongoDB for ease of use.
|
||||||
|
|
||||||
|
Please note that WireChan is a work in progress, and there may be issues with the database or server configurations. Documentation will be updated as the project evolves.
|
||||||
|
|
||||||
|
## Important to know!
|
||||||
|
Wirechan doesnt provide the database to the project (yet).
|
||||||
57
app.py
57
app.py
|
|
@ -1,11 +1,25 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ------------------------------------
|
||||||
|
# Wirechan was written by @hornet
|
||||||
|
# and represents a University project
|
||||||
|
# for his legitable proof of coding.
|
||||||
|
# (c) by hornetmaiden(hornet)
|
||||||
|
# Written in 2024
|
||||||
|
# ------------------------------------
|
||||||
|
import os
|
||||||
from flask import Flask, url_for, redirect, render_template, request, session, Response
|
from flask import Flask, url_for, redirect, render_template, request, session, Response
|
||||||
|
from flask_wtf.csrf import CSRFProtect
|
||||||
from pymongo import MongoClient
|
from pymongo import MongoClient
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = 'secret_key' #change this to a random string
|
app.secret_key = os.getenv('SECRET_KEY', 'fallback_secret_key') #change this to a random string
|
||||||
|
csrf = CSRFProtect(app)
|
||||||
|
|
||||||
#initialize the databases
|
#initialize the databases
|
||||||
client = MongoClient('localhost', 27017) #change this if you are using a different host/port
|
client = MongoClient('localhost', 27017) #change this if you are using a different host/port
|
||||||
|
|
@ -13,7 +27,10 @@ db = client.flask_db
|
||||||
posts_collection = db.posts_collection
|
posts_collection = db.posts_collection
|
||||||
users_collection = db.users_collection
|
users_collection = db.users_collection
|
||||||
nuke_counter = db.nuke_counter
|
nuke_counter = db.nuke_counter
|
||||||
isAdmin = False
|
if session.get('username') == 'admin': # Safely check if the user is an admin
|
||||||
|
isAdmin = True # Set isAdmin based on session
|
||||||
|
else:
|
||||||
|
isAdmin = False
|
||||||
|
|
||||||
#app routes
|
#app routes
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
|
|
@ -36,37 +53,35 @@ def board(board_name):
|
||||||
|
|
||||||
posts = posts_collection.find({'board_name': board_name}).sort('timestamp', -1)
|
posts = posts_collection.find({'board_name': board_name}).sort('timestamp', -1)
|
||||||
display_name = next((link['display_name'] for link in links if link['name'] == board_name), board_name)
|
display_name = next((link['display_name'] for link in links if link['name'] == board_name), board_name)
|
||||||
if isAdmin == True or ('username' in session and session['username'] == 'admin'):
|
if session.get('username') == 'admin':
|
||||||
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts, admin=admin)
|
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts, admin=True)
|
||||||
else:
|
else:
|
||||||
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts, admin=None)
|
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts, admin=None)
|
||||||
|
|
||||||
#posting API
|
#posting API
|
||||||
@app.route('/post', methods=['POST'])
|
@app.route('/post', methods=['POST'])
|
||||||
def post():
|
def post():
|
||||||
board_name = request.form['board_name']
|
board_name = bleach.clean(request.form['board_name']) # Sanitize input
|
||||||
content = request.form['content']
|
content = bleach.clean(request.form['content'])
|
||||||
if 'image' in request.files:
|
|
||||||
image = request.files['image']
|
image = request.files['image'] if 'image' in request.files else None
|
||||||
else:
|
timestamp = datetime.now()
|
||||||
image = None
|
username = session.get('username', 'Anonymous') # Use session for username
|
||||||
timestamp = datetime.now()
|
|
||||||
if 'user_id' not in session:
|
|
||||||
username = 'Anonymous'
|
|
||||||
else:
|
|
||||||
username = session['username']
|
|
||||||
|
|
||||||
#insert the post into MongoDB
|
|
||||||
post_data = {
|
post_data = {
|
||||||
'board_name': board_name,
|
'board_name': board_name,
|
||||||
'content': content,
|
'content': content,
|
||||||
'timestamp': timestamp,
|
'timestamp': timestamp,
|
||||||
'username' : username
|
'username': username
|
||||||
}
|
}
|
||||||
|
|
||||||
if image != None:
|
if image and allowed_file(image.filename):
|
||||||
post_data['image'] = image.read()
|
post_data['image'] = image.read()
|
||||||
|
|
||||||
posts_collection.insert_one(post_data)
|
try:
|
||||||
|
posts_collection.insert_one(post_data)
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error inserting post: {e}", 500
|
||||||
|
|
||||||
return redirect(url_for('board', board_name=board_name))
|
return redirect(url_for('board', board_name=board_name))
|
||||||
#image API
|
#image API
|
||||||
|
|
@ -89,10 +104,12 @@ def login_post():
|
||||||
|
|
||||||
user = users_collection.find_one({'username': username})
|
user = users_collection.find_one({'username': username})
|
||||||
if user and check_password_hash(user['password'], password):
|
if user and check_password_hash(user['password'], password):
|
||||||
|
session.clear()
|
||||||
session['user_id'] = str(user['_id'])
|
session['user_id'] = str(user['_id'])
|
||||||
session['username'] = username
|
session['username'] = username
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
elif user == 'admin' and check_password_hash(user['password'], password):
|
elif user == 'admin' and check_password_hash(user['password'], password):
|
||||||
|
session.clear()
|
||||||
session['user_id'] = str(user['_id'])
|
session['user_id'] = str(user['_id'])
|
||||||
session['username'] = 'admin'
|
session['username'] = 'admin'
|
||||||
isAdmin = True
|
isAdmin = True
|
||||||
|
|
@ -109,7 +126,7 @@ def register():
|
||||||
def register_post():
|
def register_post():
|
||||||
username = request.form['username']
|
username = request.form['username']
|
||||||
password = request.form['password']
|
password = request.form['password']
|
||||||
hashed_password = generate_password_hash(password, method='pbkdf2:sha256')
|
hashed_password = generate_password_hash(password, method='argon2')
|
||||||
regalert = ''
|
regalert = ''
|
||||||
|
|
||||||
if users_collection.find_one({'username': username}):
|
if users_collection.find_one({'username': username}):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
FlasK
|
FlasK
|
||||||
pymongo
|
Flask-WTF
|
||||||
|
bleach
|
||||||
bson
|
bson
|
||||||
|
pymongo
|
||||||
werkzeug
|
werkzeug
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
<div class="link-container">
|
<div class="link-container">
|
||||||
<h1>login</h1>
|
<h1>login</h1>
|
||||||
<form action="{{ url_for('login_post') }}" method="post">
|
<form action="{{ url_for('login_post') }}" method="post">
|
||||||
|
{{ csrf_token() }} <!-- Add this line to enable CSRF -->
|
||||||
<label for="username">username:</label>
|
<label for="username">username:</label>
|
||||||
<input type="text" id="username" name="username" required>
|
<input type="text" id="username" name="username" required>
|
||||||
<br>
|
<br>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<h1>register</h1>
|
<h1>register</h1>
|
||||||
<h4>{{ regalert }}</h4>
|
<h4>{{ regalert }}</h4>
|
||||||
<form action="{{ url_for('register_post') }}" method="post">
|
<form action="{{ url_for('register_post') }}" method="post">
|
||||||
|
{{ csrf_token() }} <!-- Add this line to enable CSRF -->
|
||||||
<label for="username">username:</label>
|
<label for="username">username:</label>
|
||||||
<input type="text" id="username" name="username" required>
|
<input type="text" id="username" name="username" required>
|
||||||
<br>
|
<br>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue