Giter Club home page Giter Club logo

gochan's People

Contributors

chebyrash avatar comraderat avatar deepsource-autofix[bot] avatar deepsourcebot avatar dependabot[bot] avatar eggbertx avatar grosa1 avatar onekopaka avatar pqyptixa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

gochan's Issues

Optimise batch update

Batch update is possibly slow due to sending the update queries one by one, for possibly thousands upon thousands of queries.

Maybe a better method is possible? Past attempt was manually making one giant sql command but that might lead to issues since some drivers only support up to an X amount of ? placeholders.

sql: no rows in result set

Log:

gochan[25281]: Starting gochan v2.11.1., using verbosity level 1
gochan[25281]: Initializing server...
gochan[25281]: failed: [ERROR] src/gochan.go:27: sql: no rows in result set

Environment: 10.3.18-MariaDB-0+deb10u1-log Debian 10

Database:

MariaDB [gochan]> show tables;
+------------------+
| Tables_in_gochan |
+------------------+
| gc_announcements |
| gc_appeals       |
| gc_banlist       |
| gc_boards        |
| gc_embeds        |
| gc_info          |
| gc_links         |
| gc_posts         |
| gc_reports       |
| gc_sections      |
| gc_sessions      |
| gc_staff         |
| gc_wordfilters   |
+------------------+

Config:

{
	"ListenIP": "127.0.0.1",
	"Port": 8080,
	"FirstPage": ["index.html","board.html","firstrun.html"],
	"Username": "gochan",
	"UseFastCGI": false,

	"DocumentRoot": "html",
	"TemplateDir": "templates",
	"LogDir": "log",

	"DBtype": "mysql",
	"DBhost_alt": "tcp(127.0.0.1:3306)",
	"_comment": "gochan can use either a URL or a UNIX socket for MySQL connections",
	"DBhost": "unix(/var/run/mysqld/mysqld.sock)",
	"DBname": "gochan",
	"DBusername": "gochan",
	"DBpassword": "password",
	"DBprefix": "gc_",

	"Lockdown": false,
	"LockdownMessage": "This imageboard has temporarily disabled posting. We apologize for the inconvenience",
	"Sillytags": ["Admin","Mod","Janitor","Faget","Kick me","Derpy","Troll","worst pony"],
	"UseSillytags": false,
	"Modboard": "staff",

// ...

	"Styles": [
		{ "Name": "Pipes", "Filename": "pipes.css" },
		{ "Name": "Burichan", "Filename": "burichan.css" },
		{ "Name": "Photon", "Filename": "photon.css" }
	],
	"DefaultStyle": "pipes.css",

	"AllowDuplicateImages": true,
	"AllowVideoUploads": true,
	"NewThreadDelay": 30,
	"ReplyDelay": 7,
	"MaxLineLength": 150,
	"ReservedTrips": [
		"thischangesto##this",
		"andthischangesto##this"
	],

	"ThumbWidth": 200,
	"ThumbHeight": 200,
	"ThumbWidth_reply": 125,
	"ThumbHeight_reply": 125,
	"ThumbWidth_catalog": 50,
	"ThumbHeight_catalog": 50,

	"ThreadsPerPage": 15,
	"PostsPerThreadPage": 50,
	"RepliesOnBoardPage": 3,
	"StickyRepliesOnBoardPage": 1,
	"BanColors": [
		"admin:#0000A0",
		"somemod:blue"
	],
	"BanMsg": "USER WAS BANNED FOR THIS POST",
	"EmbedWidth": 200,
	"EmbedHeight": 164,
	"ExpandButton": true,
	"ImagesOpenNewTab": true,
	"MakeURLsHyperlinked": true,
	"NewTabOnOutlinks": true,

	"MinifyHTML": true,
	"MinifyJS": true,

	"DateTimeFormat": "Mon, January 02, 2006 15:04 PM",
	"AkismetAPIKey": "",
	"UseCaptcha": false,
	"CaptchaWidth": 240,
	"CaptchaHeight": 80,
	"CaptchaMinutesTimeout": 15,
	"EnableGeoIP": true,
	"_comment": "set GeoIPDBlocation to cf to use Cloudflare's GeoIP",
	"GeoIPDBlocation": "/usr/share/GeoIP/GeoIP.dat",
	"MaxRecentPosts": 3,
	"RecentPostsWithNoFile": false,
	"Verbosity": 1,
	"EnableAppeals": true,
	"MaxLogDays": 14,
	"_comment": "Set RandomSeed to a (preferrably large) string of letters and numbers",
	"RandomSeed": "seed"
}

Add a plugin system

  • gochan will likely have a scripted plugin system, most likely using a (hopefully) lightweight Lua VM like go-lua
  • native Go plugins may also be supported, which could possibly allow for faster plugins, depending on how lightweight the Go plugins are compared to whatever Lua VM we use.

If native Go plugins end up being supported, they would only be supported in Linux, FreeBSD, and macOS, since those are currently the only operating systems that support Go plugins. Manual build constraints would be used to have a separate source file that would throw an error when gochan starts if the configuration file references any plugins in an unsupported operating system, rather than failing at build time. This would avoid potential confusion.

Error when attempting to create new boards

I've been playing with gochan a bit.

In src/manage.go:738, an slice ( []interface{}{board} ) is being passed to the manage_boards_tmpl template (file manage_boards.html).

				if err := manage_boards_tmpl.Execute(manageBoardsBuffer, map[string]interface{}{
					"board":       []interface{}{board},
					"section_arr": all_sections,
				}); err != nil {

However, manage_boards.html doesn't range over the slice, so when one goes to the "Manage boards" menu, it shows an error under "Create new board":
template: manage_boards.html:20:72: executing "manage_boards.html" at <.board.Locked>: can't evaluate field Locked in type interface {}

What's the logic behind this code? From what I can see, "board" here contains the default configurations for new boards, so why pass an slice instead of simply "board"?

Easier of use

ESL:
Why no sqlite? It would be easier rather than having docker, just a simple .sh to "run".

Anyways when using ./build.py docker

# github.com/gochan-org/gochan/cmd/gochan
/usr/local/go/pkg/tool/linux_arm64/link: running gcc failed: exit status 1
collect2: fatal error: cannot find 'ld'
compilation terminated.

Failed building gochan, see command output for details
Service 'gochan' failed to build: The command './build.py' returned a non-zero code: 1
Failed starting a docker container, exited with status code 1

New board

How to create new boards? In manage?action=boards the "create new board" area is blank, no buttons visible. Also, when in the admin area the quick reply posting dialog box pops up, not sure if that is intentional or not. VERY nice looking app, I have hope that gochan will develop so people can use it. Your board is the coolest one on the internet, I love it.

Help with Docker install

Hello, thanks for making gochan.

I'm fairly nooby when it comes to Docker but I'm trying to spin up a local install and I'm faced with this error after running docker-compose -f docker-compose-mariadb.yaml up --build:

dfdsf

What am I doing wrong? What's this js thing? Is this a bug?

What I have and what I did:

  • Server running Debian Bullseye
  • Installed Docker, Docker Compose and Portainer
  • All running fine, server accessible from the outside, ports 80/443 forwarded
  • Do a git clone of this repo to my root folder
  • Edit docker-compose-mariadb.yaml
  • cd into /gochan/docker folder and run docker-compose -f docker-compose-mariadb.yaml up --build
  • Build gets stuck forever at error in image above, docker-gochan-1 goes "exited"

Thanks for any help, and happy new year.

Implement post editing

Posts should be editable

  • Name, email and title should be editable
  • Text should be editable
  • Files should be editable
    - [ ] This functionality should only be available to moderators and up

just board

Can't modify or delete the board. Maybe related to this?

Error: 404 Not Found from 127.0.0.1 @ /javascript/manage.js

Also, when you specify a user in a service file then run this, board can not be created. Assme the directory name is a.

ERROR: directory //home/wwwroot/b/html/a/ already exists!

This is my service file:

[Unit]
Description=gochan Daemon
After=network.target

[Service]
WorkingDirectory=/home/wwwroot/b
ExecStart=/home/wwwroot/b/gochan
User=username
Restart=always

[Install]
WantedBy=multi-user.target

Already chmod -R username the whole gochan folder for this user.

Rework ban system

  • Rework ban system to ban via post id and/or via file
  • Hide the IP address from the frontend.
  • Rework should include filename bans, username bans, ip bans.

Completely phase out Vagrant to be replaced by Docker

Vagrant no longer boots the development machine. In Linux, it causes the host machine to completely lock up, requiring a hard boot. In Windows, the VM goes into what appears to be a boot loop. In addition, Docker appears to be more popular anyway.

Can't login after a fresh install

So I already know the default username and password:
image

But it won't log in...

image

No error output in browser console.

Gochan log:

Feb 08 20:36:34 systemd[1]: Started gochan Daemon.
Feb 08 20:36:35 gochan[10263]: Starting gochan v2.11.2., using verbosity level 1
Feb 08 20:36:35 gochan[10263]: Initializing server...
Feb 08 20:36:35 gochan[10263]: This looks like a new installation. Creating /test/ and a new staff member.
Feb 08 20:36:35 gochan[10263]: Username: admin
Feb 08 20:36:35 gochan[10263]: Password: password
Feb 08 20:36:35 gochan[10263]: Failed creating /test/ with error: [ERROR] src/gochan.go:27: Error 1364: Field 'default_style' doesn't have a default value
Feb 08 20:36:35 gochan[10263]: Loading and parsing templates...
Feb 08 20:36:35 gochan[10263]: Built gochan.min.js and consts.js successfully.

Improve unit test coverage and quality

Packages

  • cmd/gochan
  • cmd/gochan/migration/internal/common
  • cmd/gochan/migration/internal/gcupdate
  • cmd/gochan/migration/internal/kusabax
  • cmd/gochan/migration/internal/pre2021
  • cmd/gochan/migration/internal/tinyboard
  • building
  • config
  • events
  • gcplugin
  • gcsql
  • gcsql/initsql
  • gctemplates
  • gcutil
  • manage
  • posting
  • posting/geoip
  • posting/uploads
  • posting/uploads/inituploads
  • server
  • server/serverutil

Templates

Template tests should be stored in the templatetests directory, with the package set to gctemplates_test

  • banpage.html
  • boardpage.html
  • captcha.html
  • catalog.html
  • consts.js
  • error.html
  • front.html
  • front_intro.html
  • manage_announcements.html
  • manage_appeals.html
  • manage_bans.html
  • manage_boards.html
  • manage_dashboard.html
  • manage_filebans.html
  • manage_fixthumbnails.html
  • manage_ipsearch.html
  • manage_login.html
  • manage_namebans.html
  • manage_recentposts.html
  • manage_reports.html
  • manage_sections.html
  • manage_staff.html
  • manage_templateoverride.html
  • manage_threadattrs.html
  • manage_viewlog.html
  • manage_wordfilters.html
  • movethreadpage.html
  • page_footer.html
  • page_header.html
  • postbox.html
  • post_edit.html
  • post_flag.html
  • post.html
  • threadpage.html
  • topbar.html

Finish GeoIP support

The next release (3.10.0) should have GeoIP support finished, with country flags visible on posts, configurable on a per-board basis, or globally enabled

  • Country flags on posts
  • GeoIP flag usage
  • Country detection via geoip (MaxMind GeoIP2/GeoLite2 DB)
  • Legacy GeoIP database support
  • Cloudflare IP via CF-IPCountry header
  • Extendable via Lua

Currently, this is what will likely be used in gochan.json for GeoIP/flag configuration, though this may changed. Comments are included for explanation

{
	// SystemCriticalConfig.GeoIP should be a pointer in the BoardConfig struct, if it is non-nil,
	// GeoIP is assumed to be used
	"GeoIP": {
		// GeoIPType valid values:
		// "" or "none": not used, DBLocation and FlagOptions are ignored
		// "legacy": legacy/MaxMind GeoIP v1 (usually a .dat extension), may or may not end up being supported
		// "geoip2", "mmdb": MaxMind GeoIP2 database support
		// "cloudflare": Use Cloudflare's CF-IPCountry header, only usable if you are using Cloudflare and it is enabled
		"GeoIPType": "legacy",
		"DBLocation": "/path/to/db.{dat,mmdb}"
	},
	// BoardConfig.FlagOptions determines whether GeoIP is enabled for the board (or globally)
	// and what custom country flags are 
	"FlagOptions" {
		"EnableGeoIPFlag": true,
		"EnableNoFlag": true, // if enabled, a "No flag" option will be available in the dropdown and if selected, the post won't show a flag
		"CustomCountries": [
			{"Name": "Benis", "Flag": "spurdo.png"},
			{"Name": "HONK!", "Flag": "clown.png"}
		]
	}
}

For the most up to date version of GeoIP and custom flag configuration as development continues, see gochan.example.json in the geoip branch.

Add cache layer on top of prepareSQL / implement caching

Issue consists of two parts:

  1. No sql is cached at all because all statements are closed in the exec-like functions. (which removes the cache). Constantly reused sql statements should never be closed.
  2. We can possibly save some performance. If db.prepare doesnt internally cache based on string input, we need to implement manual caching of prepared statements based on hashed string input.

--- old ---

Adding a cache layer on top of/directly at the top of prepareSQL would avoid re-formatting already existing queries.

Current situation:

  1. Query is formatted/replaced according to database
  2. Query is passed to stmt which has it cached and returns cached version
  3. Query is excecuted and then closed, removing the cache.

New situation:
In prepareSQL: Query is hashed and cached stmt statament is returned (if not closed)

Future of this project.

I was wondering if you guys are planning to further develop this project.

I wanted to propose we change our HTTP server to a faster one, use Docker & Kubernetes for development / production and think about shifting media files to cloud storage like a CDN or S3.

In my opinion we should start developing a REST API which would allow us to separate that HTML and Go backend code.

A lot of your SQL code is vulnerable to SQL injection attacks. Using parameterized queries is more secure than embedding the parameters right into the query. This also allows for quicker SQL queries as the request only has to be compiled once and can be reused.

Another execution error (hope this isn't a bother).

I'm now getting this when I try to execute:

Mar 23 22:10:17 grusha systemd[1]: Started gochan Daemon. Mar 23 22:10:17 grusha gochan[112613]: Starting gochan v3.5.0 Mar 23 22:10:17 grusha gochan[112613]: Connected to database Mar 23 22:10:17 grusha gochan[112613]: Failed to initialize the database: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF EXISTS wordfilters_board_id_fk' at line 1 Mar 23 22:10:17 grusha systemd[1]: gochan.service: Main process exited, code=exited, status=1/FAILURE Mar 23 22:10:17 grusha systemd[1]: gochan.service: Failed with result 'exit-code'.

What file is it getting this from so I could check line 1?

Custom top bar board formatting

Implement custom top bar formatting, accessible via the global config.
This would allow admins to change the top navbar board layout to whatever they want.

Would probably look something like this:

  • All text is normal text
  • Board links are inserted by enclosing a URI between <>
  • To write < or > you escape it with a backslash like \< \> so

image display

board-gochan

See on far left how it says /test/src? After posting, one has to click that link to make the image show up. Not trying to harp on you, hopefully this post is helpful. Gochan is cool and is my fav board!!!!!

Posting to a board with a non-contiguous id causes a panic when trying to post to it

Having boards with ids that are not contiguous is not handled well, as the array returned by getBoardArr(nil, "") has all boards numbered from 0 to n, where n is the number of boards. However if a board has an id that is not contiguous with the previous board's ID, the attempts to access that board from that array, will be incorrect, as it will be attempting to access the incorrect entry in this boards array.

Use gometalinter

Please use gometalinter (https://github.com/alecthomas/gometalinter), which is a tool that

Concurrently run Go lint tools and normalise their output

I ran it againt the gochan code and got:

$ gometalinter --deadline 900s | wc -l
431

Using it is easy (as explained in https://github.com/alecthomas/gometalinter#installing and https://github.com/alecthomas/gometalinter#quickstart):

$ go get -u github.com/alecthomas/gometalinter
$ gometalinter --install
$ cd /path/to/src
$ gometalinter

Most of the warnings are formatting warnings, but some could point to serious bugs:

manage.go:83:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:93:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:141:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:146:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:162:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:225:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:339:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:389:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:441:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:492:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:586:: warning: Expect directory permissions to be 0700 or less,MEDIUM,HIGH (gas)
manage.go:592:: warning: Expect directory permissions to be 0700 or less,MEDIUM,HIGH (gas)
manage.go:598:: warning: Expect directory permissions to be 0700 or less,MEDIUM,HIGH (gas)
manage.go:604:: warning: Expect directory permissions to be 0700 or less,MEDIUM,HIGH (gas)
manage.go:610:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:653:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:718:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:737:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:816:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:839:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:887:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:906:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
manage.go:917:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:7:: warning: Use of weak cryptographic primitive,HIGH,HIGH (gas)
posting.go:88:: warning: Expect directory permissions to be 0700 or less,MEDIUM,HIGH (gas)
posting.go:118:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:129:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:197:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:227:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:239:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:379:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:398:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:435:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:466:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:473:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:491:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:531:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
posting.go:566:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:584:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:627:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:663:: warning: Subprocess launching with variable.,HIGH,HIGH (gas)
posting.go:677:: warning: Subprocess launching with variable.,HIGH,HIGH (gas)
posting.go:736:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:828:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:925:: warning: Use of weak cryptographic primitive,MEDIUM,HIGH (gas)
posting.go:928:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
posting.go:967:: warning: Subprocess launching with variable.,HIGH,HIGH (gas)
posting.go:1149:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:216:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:254:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:272:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:296:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:313:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:322:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:330:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
server.go:337:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
sql.go:36:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
sql.go:69:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
sql.go:112:: warning: SQL string formatting,MEDIUM,HIGH (gas)
types.go:472:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
types.go:481:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
types.go:489:: warning: Expect file permissions to be 0600 or less,MEDIUM,HIGH (gas)
util.go:5:: warning: Use of weak cryptographic primitive,HIGH,HIGH (gas)
util.go:49:: warning: Use of weak cryptographic primitive,MEDIUM,HIGH (gas)
util.go:168:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
util.go:264:: warning: SQL string concatenation,MEDIUM,HIGH (gas)
util.go:323:: warning: SQL string concatenation,MEDIUM,HIGH (gas)

Unit test sql

Write a system to unit test existing SQL against real running databases, starting with queries that are non-deprecated with the current version of the database design.
Use vagrant (or whatever we use to virtual box) to automatically set it each database version and run it?

Needed:

  • A project that imports the sql package, can connect to a database based on a testing config, allows you to define unit tests on specific functions with buildup (create database, execute population script, add mock data), excecution (run command), assertion and breakdown (drop database)

Would like:

  • Possibly using vagrant/docker or whatever we use to set up a virtual box with said project for each database so tests can easily be run by any programmer anywhere.
  • Jenkins/automatic testing on a server to do it for you.

Issue running gochan executable: "Error parsing gochan.json: invalid character ']' looking for beginning of valueinvalid ListenIP value: "" "

For some reason, when I try to run GoChan through systemd, it fails and gives me this error:
image

Upon further investigation, I'm given this error when running the executable alone.
image2

I checked my gochan.json file, and I do not see a closing bracket anywhere in the ListenIP line.
As a result, I have no clue what the issue could be, or why I'm given a "gochan.json can't be found" error when it is being read from the second screenshot.

Create multi-board and multi-board catalog (overboard).

  • Implement it in such a fashion that it takes a list of board which it should cover
  • Implement a single overboard and a catalog for the overboard that covers all board, using the above functionality

Reasoning:
By implementing it generically it can be used for a sfw overboard, a nsfw overboard, and in the future possible allow for custom personalized overboards.

Replace gochan-migration with a plugin

Rather than going through the trouble of writing a system for reliably copying all of the data from the database of another imageboard system (for example, TinyBoard) for it to be "translated" into gochan's DB schema, it might be possible and less work to instead have a plugin do something like the reverse. So for example, a plugin might be registered in gochan.json to make gochan compatible with a TinyBoard database, handling things like staff, board, and post creation, editing, deletion, etc, via events.

This would still likely require a lot of work, but might be more feasible. It would also likely require all SQL queries to be moved to the gcsql package.

Why is there so much HTML code in your .go files?

It would be much better if you created a stable REST API for the imageboard.

Firstly, it doesn't help caching if you keep sending same HTML from the server over and over again.
Secondly, you are limiting yourself to browser viewing only, so no phone app.
Lastly, it just looks like spaghetti code.

Add image fingerprinting

Image fingerprinting, possibly via a fast perceptual hashing algorithm like ahash would make fighting spam significantly easier, without too much computational effort for the server.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.