Compare commits
483 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a75911ab7 | ||
|
|
8181d174a5 | ||
|
|
c618440878 | ||
|
|
0bc6298cc0 | ||
|
|
93b452c497 | ||
|
|
b2d46c9021 | ||
|
|
f972d91137 | ||
|
|
f8a6b32b5f | ||
|
|
439ab7583a | ||
|
|
5800b1bf1d | ||
|
|
1ba53b7688 | ||
|
|
dd2eb90230 | ||
|
|
2319327917 | ||
|
|
89dfe68b32 | ||
|
|
c4dadd21fc | ||
|
|
812d7cfd9d | ||
|
|
415f0d6e39 | ||
|
|
08d97147b8 | ||
|
|
23614275eb | ||
|
|
1eca5c59e3 | ||
|
|
91953148e8 | ||
|
|
c5a5fb57d9 | ||
|
|
5b8d338840 | ||
|
|
5bc7c92e71 | ||
|
|
f32bd8c946 | ||
|
|
ca333e06ac | ||
|
|
9aab7addb1 | ||
|
|
0b984d0dcd | ||
|
|
73b254367f | ||
|
|
a9c09e57e9 | ||
|
|
d8b57e2189 | ||
|
|
7ce22cefb7 | ||
|
|
2de555f176 | ||
|
|
68c071e318 | ||
|
|
077b61270c | ||
|
|
5975383349 | ||
|
|
46ca31066f | ||
|
|
9db627d07f | ||
|
|
014dbdfa95 | ||
|
|
ea06f5498f | ||
|
|
c2d60063ee | ||
|
|
0ebd2241e5 | ||
|
|
0aca177c86 | ||
|
|
9bb45cd896 | ||
|
|
7458a884d5 | ||
|
|
6392a606c4 | ||
|
|
693bcdeffd | ||
|
|
81a398ab26 | ||
|
|
7296bc6944 | ||
|
|
e97c4bab53 | ||
|
|
2c03b8fd6b | ||
|
|
2f3742fa7c | ||
|
|
ff816fd556 | ||
|
|
585d4cbff1 | ||
|
|
0d388b19ee | ||
|
|
a8e870a099 | ||
|
|
32c4dcbe69 | ||
|
|
a3571f541b | ||
|
|
39dbe314d6 | ||
|
|
63e2614983 | ||
|
|
0623077a40 | ||
|
|
f05d43af89 | ||
|
|
68b73ff1dd | ||
|
|
0613350420 | ||
|
|
37af910c89 | ||
|
|
6286a6529c | ||
|
|
51bdf9609f | ||
|
|
b5d60f1431 | ||
|
|
56f8fc8b91 | ||
|
|
e0de5dfbf5 | ||
|
|
d122da98b5 | ||
|
|
e6a38af5ee | ||
|
|
abf3da5900 | ||
|
|
a40aad33d1 | ||
|
|
9a6f3ef4ed | ||
|
|
372a8767ee | ||
|
|
f7a31012e8 | ||
|
|
5cf11d50d4 | ||
|
|
a4f3e4ffa4 | ||
|
|
60de698f2c | ||
|
|
1c4f4630c2 | ||
|
|
9974628f62 | ||
|
|
2ea928417d | ||
|
|
eede0c55dc | ||
|
|
c6780cfd27 | ||
|
|
34b2e18587 | ||
|
|
38d3bc4481 | ||
|
|
e556d6d2be | ||
|
|
22a3564f22 | ||
|
|
b695d97e82 | ||
|
|
64e4c3320d | ||
|
|
7c7d07434d | ||
|
|
d2b9e76389 | ||
|
|
f91bd642a5 | ||
|
|
9459e1758d | ||
|
|
24b2bd8e15 | ||
|
|
8ad13c8e45 | ||
|
|
c6e6c2e5d6 | ||
|
|
9690156fbf | ||
|
|
dea611c1ba | ||
|
|
0e0f35e6dc | ||
|
|
5370898da9 | ||
|
|
1020fae1dd | ||
|
|
6bcfff0269 | ||
|
|
5fbf75a77d | ||
|
|
86744c9349 | ||
|
|
24b6d87381 | ||
|
|
649cc96269 | ||
|
|
a9e377563d | ||
|
|
9229aa62bd | ||
|
|
f9c9028a0b | ||
|
|
5fa12dcda8 | ||
|
|
8c0a4ac6b0 | ||
|
|
bd279547d2 | ||
|
|
1ad6432576 | ||
|
|
4b007fa759 | ||
|
|
abe985b6c5 | ||
|
|
6091934884 | ||
|
|
7db701b23a | ||
|
|
00816c1a95 | ||
|
|
713f8a7d19 | ||
|
|
da42b8fc7d | ||
|
|
27bf7de803 | ||
|
|
4fd443dce4 | ||
|
|
f8d3f85a4d | ||
|
|
007851056f | ||
|
|
f97b5a56e5 | ||
|
|
7495c3e843 | ||
|
|
713ff950e7 | ||
|
|
64a7a6e6aa | ||
|
|
6aa9475c91 | ||
|
|
a9ac1207c0 | ||
|
|
539033ec6d | ||
|
|
80041baf1e | ||
|
|
b83b21df59 | ||
|
|
69c30e0685 | ||
|
|
0ed2bad9f1 | ||
|
|
41d3cb467b | ||
|
|
476ae002c2 | ||
|
|
6f0b518391 | ||
|
|
f673a10768 | ||
|
|
8668d1aa08 | ||
|
|
d2babe367b | ||
|
|
3b5937f2d9 | ||
|
|
1896060218 | ||
|
|
9d2461c716 | ||
|
|
85d60a1928 | ||
|
|
6eb42d4cf7 | ||
|
|
37df9ef131 | ||
|
|
450d07d6e5 | ||
|
|
047a63ec20 | ||
|
|
3821562cf6 | ||
|
|
85a968ad40 | ||
|
|
c169616471 | ||
|
|
c0d5800bd4 | ||
|
|
6bd5518249 | ||
|
|
b3da008694 | ||
|
|
3a2529561f | ||
|
|
110e607839 | ||
|
|
54fa915aeb | ||
|
|
273d28d237 | ||
|
|
ec56bbe8f9 | ||
|
|
9340b9088e | ||
|
|
329eca6af3 | ||
|
|
06d4535eaa | ||
|
|
9f78414098 | ||
|
|
97faee8d1d | ||
|
|
33d95c2ef3 | ||
|
|
97ee132989 | ||
|
|
ab3da1edee | ||
|
|
ba0f5471a3 | ||
|
|
9f84ab4ca9 | ||
|
|
3274536134 | ||
|
|
bc5b22f7a1 | ||
|
|
0199230489 | ||
|
|
98bb655a3c | ||
|
|
c4090303ec | ||
|
|
0be5982d39 | ||
|
|
c7975c67ef | ||
|
|
59173f055e | ||
|
|
0b8c977aad | ||
|
|
2c0426d1a4 | ||
|
|
e6de8a1d20 | ||
|
|
9ebe7d7c5d | ||
|
|
84626f6f96 | ||
|
|
3a35dc5575 | ||
|
|
13b8a18e21 | ||
|
|
4557503256 | ||
|
|
689ced2ae4 | ||
|
|
ccc5972e67 | ||
|
|
e07260d068 | ||
|
|
7854b0b81d | ||
|
|
177e0156cc | ||
|
|
10d47779d3 | ||
|
|
d26d6ecacb | ||
|
|
85200d9284 | ||
|
|
8bcd0b790c | ||
|
|
68e4e9162f | ||
|
|
05d1290344 | ||
|
|
d1bb6b59b0 | ||
|
|
64111298f6 | ||
|
|
6df6fd807a | ||
|
|
d140c9ee99 | ||
|
|
50fafb4531 | ||
|
|
5591b56df0 | ||
|
|
6041a7d608 | ||
|
|
111522d08e | ||
|
|
7d89ab06c7 | ||
|
|
cab35af8c4 | ||
|
|
5abbe123c3 | ||
|
|
404d9952f2 | ||
|
|
a6b7235b12 | ||
|
|
55f4461475 | ||
|
|
bb1c6890ac | ||
|
|
e545bab034 | ||
|
|
21ec8e5f3a | ||
|
|
35c6875b00 | ||
|
|
45f217fa78 | ||
|
|
e6ca1b07ed | ||
|
|
3e3680c9be | ||
|
|
7501dae72e | ||
|
|
93328cb480 | ||
|
|
ab69a2e9a4 | ||
|
|
a6da70e7d3 | ||
|
|
6e87271483 | ||
|
|
fed34ed622 | ||
|
|
eb5ca66330 | ||
|
|
81f11be7c5 | ||
|
|
2c9f332fb0 | ||
|
|
d6f3bdd9e8 | ||
|
|
e75cf64769 | ||
|
|
d030303ed3 | ||
|
|
9ad004e85f | ||
|
|
83a4102e38 | ||
|
|
57e2ebda6e | ||
|
|
24b6ad9276 | ||
|
|
0e28120697 | ||
|
|
775dc470e5 | ||
|
|
a929709924 | ||
|
|
c23696aae5 | ||
|
|
ed97ca881d | ||
|
|
ed041c1689 | ||
|
|
67bcbc6289 | ||
|
|
8eec2ce827 | ||
|
|
749bd5a72b | ||
|
|
d0ad0ae71d | ||
|
|
4bff278a8f | ||
|
|
6453d405a6 | ||
|
|
1614cef91f | ||
|
|
0004483395 | ||
|
|
d1d846e2fe | ||
|
|
2a267f93be | ||
|
|
3c8fa13ffe | ||
|
|
e50d145bbe | ||
|
|
f85eaf35ac | ||
|
|
d16921d727 | ||
|
|
8bb13354a2 | ||
|
|
4c9ec43d30 | ||
|
|
69ef6f2b71 | ||
|
|
39c6c6b963 | ||
|
|
5219bcefab | ||
|
|
322edd37cb | ||
|
|
edfca55b8f | ||
|
|
1c405795b9 | ||
|
|
8ebba42030 | ||
|
|
41643bc52a | ||
|
|
ad5dfca2ef | ||
|
|
a95ec269df | ||
|
|
dc3ec1c63d | ||
|
|
371256e147 | ||
|
|
edd4b13af4 | ||
|
|
b12f6421fd | ||
|
|
eb08ccb5d6 | ||
|
|
e18f91c7e5 | ||
|
|
0176f32bd4 | ||
|
|
ab83843ef6 | ||
|
|
a0823c13db | ||
|
|
26042749aa | ||
|
|
cde9c1c641 | ||
|
|
fdcd9181ad | ||
|
|
9b3c073692 | ||
|
|
ce74caabf9 | ||
|
|
70ff3f487f | ||
|
|
78025891df | ||
|
|
1044989070 | ||
|
|
34dcede98f | ||
|
|
363743ac0c | ||
|
|
92c7102c50 | ||
|
|
38085620dc | ||
|
|
320966cca3 | ||
|
|
4165a5c34b | ||
|
|
f7504c7425 | ||
|
|
8196274c0e | ||
|
|
32d4fe6307 | ||
|
|
b57778cdcf | ||
|
|
15b14980f8 | ||
|
|
82708039c2 | ||
|
|
f58f4258e8 | ||
|
|
68d011b42b | ||
|
|
fdaf1dd9da | ||
|
|
bf82420f99 | ||
|
|
6cbe15988e | ||
|
|
3094108e59 | ||
|
|
c084518622 | ||
|
|
4e3d66ad52 | ||
|
|
b9e2202d04 | ||
|
|
44b63a11a0 | ||
|
|
1ad84780a8 | ||
|
|
4c822ba2cd | ||
|
|
2212f61ff0 | ||
|
|
19198738c3 | ||
|
|
7aa769d52d | ||
|
|
e4a9d8ef8c | ||
|
|
2d45920bc7 | ||
|
|
ee7004fc42 | ||
|
|
e82058d961 | ||
|
|
086eec72d8 | ||
|
|
d3a423a72f | ||
|
|
0427135322 | ||
|
|
f0ceac8d28 | ||
|
|
e263ebde0b | ||
|
|
651bd33205 | ||
|
|
7051da0e91 | ||
|
|
8dc4667666 | ||
|
|
3eba7adc1c | ||
|
|
8a7efa9929 | ||
|
|
83f5855bba | ||
|
|
c497a01e2d | ||
|
|
56b716d584 | ||
|
|
688c9a746c | ||
|
|
7027b9e297 | ||
|
|
5d191c88bc | ||
|
|
91367983ec | ||
|
|
bbba16380f | ||
|
|
80e4d7beb4 | ||
|
|
a451a6b46e | ||
|
|
75c72e177c | ||
|
|
939472f5a4 | ||
|
|
cf033b03b6 | ||
|
|
b16b0c72b0 | ||
|
|
566c88dc28 | ||
|
|
4698f7a118 | ||
|
|
5e60d20222 | ||
|
|
6cbc367630 | ||
|
|
af85eae429 | ||
|
|
5420346b36 | ||
|
|
e11978a0d9 | ||
|
|
d94813ee36 | ||
|
|
1aa4f81ae7 | ||
|
|
270e72c8eb | ||
|
|
0d1c42b086 | ||
|
|
105b314ee7 | ||
|
|
7dfc1e3418 | ||
|
|
d5b45cb58e | ||
|
|
a9ea094144 | ||
|
|
f1037d888d | ||
|
|
2a9b1f3eac | ||
|
|
bf351294b1 | ||
|
|
f93256e0d8 | ||
|
|
c1ecf14258 | ||
|
|
80e12fe0f3 | ||
|
|
f6400b3cb5 | ||
|
|
04126b743c | ||
|
|
f7211600f8 | ||
|
|
25901e3d44 | ||
|
|
97ec36feaa | ||
|
|
c5f17cf048 | ||
|
|
0b7b248ea1 | ||
|
|
2f381e7052 | ||
|
|
f006b61c4e | ||
|
|
3a13943d49 | ||
|
|
ab15a2ff33 | ||
|
|
af582eb30b | ||
|
|
471377ff2e | ||
|
|
3c4e319f06 | ||
|
|
7845131544 | ||
|
|
91971f2f3e | ||
|
|
072e36915a | ||
|
|
758a2c6bbb | ||
|
|
fc23bea021 | ||
|
|
b3f104a80a | ||
|
|
e88c8f78ba | ||
|
|
d249d373c1 | ||
|
|
8608d222c3 | ||
|
|
fcca345ba1 | ||
|
|
bc81c8e251 | ||
|
|
ccbdd33b93 | ||
|
|
7727fc76f8 | ||
|
|
bb676336db | ||
|
|
6194db1941 | ||
|
|
229ef83e35 | ||
|
|
12e887316a | ||
|
|
823af74633 | ||
|
|
441be15845 | ||
|
|
95f425c31d | ||
|
|
2366781282 | ||
|
|
69adbaca5a | ||
|
|
dd2f916aed | ||
|
|
ef71260653 | ||
|
|
0e0a9c3da9 | ||
|
|
cdc405f29e | ||
|
|
1a51354621 | ||
|
|
ac3f0eab94 | ||
|
|
c5605a4412 | ||
|
|
4e31910ed6 | ||
|
|
3b1d09072c | ||
|
|
7f56d35762 | ||
|
|
3360eaf924 | ||
|
|
51041e2dc9 | ||
|
|
6e20cb270e | ||
|
|
6019d70382 | ||
|
|
cec6f7cef5 | ||
|
|
40b7e0a88b | ||
|
|
b595024585 | ||
|
|
00fbc305be | ||
|
|
5e3f2eea03 | ||
|
|
7f721eefea | ||
|
|
866196e810 | ||
|
|
8c18b4405d | ||
|
|
578d9f44b3 | ||
|
|
ab38445555 | ||
|
|
98cf765690 | ||
|
|
d742af18b5 | ||
|
|
74a1c044f0 | ||
|
|
adb3e54212 | ||
|
|
1cc4d4e858 | ||
|
|
ec8db8121f | ||
|
|
9cb8998302 | ||
|
|
2f8fd2f2b5 | ||
|
|
790c61cfdb | ||
|
|
7b3ec70a80 | ||
|
|
fcbae8cea1 | ||
|
|
569727cc96 | ||
|
|
f7fc61d493 | ||
|
|
8cbf1f217d | ||
|
|
458232d402 | ||
|
|
fcfd010e5c | ||
|
|
dca5ee7561 | ||
|
|
108f05da32 | ||
|
|
a515ba9d1f | ||
|
|
8611e2e768 | ||
|
|
20dd0c215e | ||
|
|
c91c8c08b1 | ||
|
|
9321a65f1c | ||
|
|
b2a71e1877 | ||
|
|
045e3140ad | ||
|
|
d6f073943e | ||
|
|
47f884ce98 | ||
|
|
9d815479b2 | ||
|
|
2aa2405ba7 | ||
|
|
40d6cf77ad | ||
|
|
e70c4ed84e | ||
|
|
1c61de8880 | ||
|
|
8d146ed6cd | ||
|
|
9a807bbebf | ||
|
|
61fc6d076f | ||
|
|
5a2500dffc | ||
|
|
021721d21e | ||
|
|
2304d3d8fa | ||
|
|
c340d215e0 | ||
|
|
9e0029772c | ||
|
|
1663abcbec | ||
|
|
b58e582f0a | ||
|
|
1cfa104e4c | ||
|
|
dc06baba37 | ||
|
|
838bbc20cd | ||
|
|
487e392d76 | ||
|
|
90276293e1 | ||
|
|
8411568530 | ||
|
|
de51b912ff | ||
|
|
8b206740f8 | ||
|
|
be7e510519 | ||
|
|
abefe50eb6 | ||
|
|
fb06097557 | ||
|
|
7ba0e728af | ||
|
|
f9ea948071 | ||
|
|
a2fd94a83e | ||
|
|
fd1193f73a | ||
|
|
64cd178b2a | ||
|
|
fffd5beea5 | ||
|
|
4b56272fdd | ||
|
|
1f346b9da7 | ||
|
|
cb5f7f2453 |
18
.gitignore
vendored
@@ -8,10 +8,24 @@
|
||||
.\#*
|
||||
|
||||
# srnd config files
|
||||
*.ini
|
||||
srnd.ini
|
||||
feeds.ini
|
||||
|
||||
# default article store directory
|
||||
articles
|
||||
|
||||
# generated files
|
||||
webroot
|
||||
webroot
|
||||
|
||||
# built binaries
|
||||
go
|
||||
srndv2
|
||||
|
||||
# private key
|
||||
*.key
|
||||
|
||||
# certificates
|
||||
certs
|
||||
|
||||
|
||||
rebuild.sh
|
||||
|
||||
20
README.md
@@ -1,29 +1,23 @@
|
||||
# NNTPChan #
|
||||
|
||||
NNTPChan (previously known as overchan) is a decentralized imageboard that uses nntp to synchronize content between many different servers. It utilizes cryptograpghicly signed posts to perform optional/opt-in decentralized moderation.
|
||||
NNTPChan (previously known as overchan) is a decentralized imageboard that uses nntp to synchronize content between many different servers. It utilizes cryptographically signed posts to perform optional/opt-in decentralized moderation.
|
||||
|
||||
This repository contains resources used by the core daemon which is located [here](https://github.com/majestrate/srndv2) along with general documentation, [here](doc/)
|
||||
|
||||
## getting started ##
|
||||
|
||||
After you [built and installed the daemon](doc/build.md) and [set up your database](doc/database.md), clone this repository and start up the daemon
|
||||
|
||||
# clone it
|
||||
git clone https://github.com/majestrate/nntpchan ~/nntpchan
|
||||
cd ~/nntpchan
|
||||
[see build documentation](doc/build.md)
|
||||
|
||||
# set up the workspace
|
||||
srndv2 setup
|
||||
---
|
||||
|
||||
# run the daemon
|
||||
srndv2 run
|
||||
*PLEASE* report any bugs you find while setting up or building [(here)](https://github.com/majestrate/nntpchan/issues) so that the problems get fixed :^)
|
||||
|
||||
IRC:
|
||||
|
||||
Then open http://127.0.0.1:18000/ukko.html in your browser.
|
||||
[freenode: #nntpchan](https://webchat.freenode.net/?channels=#nntpchan)
|
||||
|
||||
*PLEASE* report any bugs you find while setting up or building [(here)](https://github.com/majestrate/nntpchan/issues) so that the problems get fixed (^:
|
||||
|
||||
For peering requests, questions or support find me on [rizon](https://qchat.rizon.net/?channels=#nntpchan) as \__uguu\__
|
||||
[rizon: #nntpchan](https://qchat.rizon.net/?channels=#nntpchan)
|
||||
|
||||
|
||||
Like this project? Fund it:
|
||||
|
||||
6
TODO.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## TODO ##
|
||||
|
||||
* extra stylesheets
|
||||
* more alternative templates
|
||||
* javascript free mod panel
|
||||
* liveui
|
||||
33
build.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
root=$(readlink -e $(dirname $0))
|
||||
|
||||
tags=""
|
||||
|
||||
help_text="usage: $0 [--disable-redis]"
|
||||
|
||||
# check for help flags first
|
||||
for arg in $@ ; do
|
||||
case $arg in
|
||||
-h|--help)
|
||||
echo $help_text
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# check for build flags
|
||||
for arg in $@ ; do
|
||||
case $arg in
|
||||
"--disable-redis")
|
||||
tags="$tags -tags disable_redis"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
cd $root
|
||||
export GOPATH=$root/go
|
||||
mkdir -p $GOPATH
|
||||
go get -v -u $tags github.com/majestrate/srndv2
|
||||
cp -a $GOPATH/bin/srndv2 $root
|
||||
echo "Built"
|
||||
11
contrib/configs/nginx/nntpchan
Normal file
@@ -0,0 +1,11 @@
|
||||
# using srndv2 behind nginx with a prefix
|
||||
# make sure to set prefix=/nntpchan/ for section frontend in srnd.ini
|
||||
server {
|
||||
listen 80;
|
||||
location /nntpchan/(.*) {
|
||||
client_max_body_size 50M;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_pass http://[::1]:18000/$1;
|
||||
}
|
||||
}
|
||||
76
contrib/doc/dusty_setup.md
Normal file
@@ -0,0 +1,76 @@
|
||||
Date: October 2015.
|
||||
|
||||
Getting the srndv2 tool
|
||||
|
||||
I am using debian, you should be able to use most any linux distro for this. Known to work are: debian, arch linux, <TODO: add more>.
|
||||
|
||||
Most commands should be done as a normal user, but some special commands need to be done as root. I find it useful to have two terminals open. I'll denote normal user level commands with '$' and root command with '#'.
|
||||
|
||||
Some dependencies you will need to install (as root) are:
|
||||
|
||||
# apt-get install build-essential golang git
|
||||
# apt-get install libsodium-dev ffmpegthumbnailer
|
||||
# apt-get install imagemagick ffmpegthumbnailer sox
|
||||
|
||||
The source code is in these two repos:
|
||||
|
||||
* https://github.com/majestrate/nntpchan
|
||||
* https://github.com/majestrate/srndv2
|
||||
|
||||
set up your GOPATH (notes on that here: https://golang.org/doc/code.html#GOPATH ) and then install and build it:
|
||||
|
||||
$ go get -u github.com/majestrate/srndv2
|
||||
|
||||
If that command didn't work read the errors and check if you lacked any dependencies.
|
||||
|
||||
Now you have the srndv2 tool which you can run, but it will not work yet: You need to step up an SQL database first.
|
||||
|
||||
--------------
|
||||
|
||||
Setting up an SQL database
|
||||
|
||||
* https://wiki.postgresql.org/wiki/Detailed_installation_guides
|
||||
|
||||
Install postgresql.
|
||||
|
||||
# apt-get install postgresql postgresql-client
|
||||
|
||||
Create a postgresql user called 'srnd' and a database 'srnd':
|
||||
|
||||
# su postgres
|
||||
$ whoami
|
||||
postgres
|
||||
$ psql -f nntpchan/nntp.psql
|
||||
|
||||
TODO: Get correct filename here.
|
||||
|
||||
Test if you can log in to that SQL user this way:
|
||||
|
||||
$ psql -d srnd -U srnd
|
||||
|
||||
If there is an issue with that try the following from the debian wiki:
|
||||
|
||||
------------
|
||||
edit pg_hba.conf in /etc/postgresql/X.Y/main/pg_hba.conf
|
||||
|
||||
local all all trust # replace ident or peer with trust
|
||||
|
||||
reload postgresql
|
||||
|
||||
# /etc/init.d/postgresql reload
|
||||
------------
|
||||
|
||||
hit Contol-D to get back your root terminal after doing this.
|
||||
|
||||
|
||||
Once SQL setup is successful..
|
||||
|
||||
|
||||
Now as your regular user that installed the srndv2 tool, you should be able to set up srndv2
|
||||
|
||||
First clone nntpchan and cd into it, then ask the srndv2 tool to setup your node:
|
||||
|
||||
$ git clone https://github.com/majestrate/nntpchan.git
|
||||
$ cd nntpchann
|
||||
ntpchan/$ srndv2 setup
|
||||
ntpchan/$ srndv2 tool keygen
|
||||
BIN
contrib/static/404.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
contrib/static/about.mp3
Normal file
BIN
contrib/static/banner_0.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
contrib/static/banner_1.jpg
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
contrib/static/banner_2.jpg
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
contrib/static/bg.png
Normal file
|
After Width: | Height: | Size: 135 B |
84
contrib/static/bloodgod.css
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
bloodgod theme css override
|
||||
*/
|
||||
|
||||
body {
|
||||
color: #666;
|
||||
background: #111;
|
||||
}
|
||||
|
||||
|
||||
input, textarea, button, input[type="text"], input[type="password"],
|
||||
input[type="checkbox"], input[type="file"], input[type="submit"],
|
||||
input[type="button"] {
|
||||
color: #666;
|
||||
background: #050505;
|
||||
border-color: #D80000;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background: #980000;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#captcha_img, pre {
|
||||
background: #D80000;
|
||||
}
|
||||
|
||||
.reply, .ukko_thread_header {
|
||||
border-color: #CA0101;
|
||||
}
|
||||
|
||||
.ukko_thread_header {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
hr, .name {
|
||||
color: #6B1919;
|
||||
}
|
||||
|
||||
.subject {
|
||||
color: #4E0000;
|
||||
}
|
||||
|
||||
.reply , .ukko_thread_header {
|
||||
background: #0C0C0C;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #500707;
|
||||
}
|
||||
|
||||
.postno, .postnol {
|
||||
color: #B70000;
|
||||
}
|
||||
|
||||
.postform >tr, th {
|
||||
background: #6B1919;
|
||||
}
|
||||
|
||||
table tbody tr:nth-of-type( even ) {
|
||||
background-color: #430000;
|
||||
}
|
||||
|
||||
table thead th {
|
||||
color: #6B1919;
|
||||
background: #430000;
|
||||
border-color: #270000;
|
||||
}
|
||||
|
||||
.navbar-sep {
|
||||
color: #270000;
|
||||
}
|
||||
|
||||
.navbar-link > label:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.origin > img , .not_found > img {
|
||||
-webkit-filter: invert(1);
|
||||
filter: invert(1);
|
||||
}
|
||||
52
contrib/static/chen-chan-faq.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!doctype html><html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>nntpchan faq</title></head><body>
|
||||
<audio loop controls><source src="/static/about.mp3" type="audio/mpeg">[can't play audio.]</audio>
|
||||
<p>nntpchan faq</p>
|
||||
<dl>
|
||||
<dt>What is nntpchan?</dt>
|
||||
<dd>NNTPCchan is a federated imageboard that spans across several networks including tor, i2p and anonet. There are no central servers so that as long as 1 server is left the forum will continue to function.</dd>
|
||||
<br>
|
||||
<dt>How is this different from *chan?</dt>
|
||||
<dd>NNTPChan is by design invulnerable to global censorship. All moderation is local to each server.</dd>
|
||||
<br>
|
||||
<dt>How does moderation work then?</dt>
|
||||
<dd>Moderation is done with our special tripcodes (ed25519-sha512 signed posts). Anyone can give moderation suggestions, but that doesn't mean anyone will accept them. Those who trust the actions of a moderator can have their frontend whitelist the moderation actions and have them performed without oversight by another moderator.</dd>
|
||||
<br>
|
||||
<dt>How can I remove content from nntpchan completely?</dt>
|
||||
<dd>‾\(._.)/‾ I don't know. You probably can't unless every server agrees to remove the content, even then, nothing prevents someone from reposting it. You can't delete what you post on the internet.</dd>
|
||||
<br>
|
||||
<dt>do you allow child porn?</dt>
|
||||
<dd>no.</dd>
|
||||
<br>
|
||||
<dt>Do you allow XYZ content?</dt>
|
||||
<dd>If it violates USA Law or causes problems with my host, no. Otherwise, probably.</dd>
|
||||
<br>
|
||||
<dt>Someone posted something I don't like but it's not illegal</dt>
|
||||
<dd>That is not my problem. All posts on this site are the responsibility of the individual poster and not the administration of this server</dd>
|
||||
<br>
|
||||
<dt>code, bugs, feature requests</dt>
|
||||
<dd><a href="https://github.com/majestrate/nntpchan/">frontend</a> <a href="https://github.com/majestrate/srndv2/">core</a></dd>
|
||||
<br></dl>
|
||||
<p>Please send any gripes/questions/inqueries/suggestions/complaints to ampernand [|at\] gmail {dot} com with subject starting with "nntpchan question"</p>
|
||||
<hr>
|
||||
<p>ucavviu7wl6azuw7.onion frontend specific</p>
|
||||
<dl>
|
||||
<dt>admin's pubkey</dt>
|
||||
<dd>06833a90237c61f59558c1726fbe71c63e972722b2cf1147867be286cb020b32<br>
|
||||
▆☃►☐▣◼◡♵☕◘♁◲◯☾◱♆▾☗▧▢☲♏░◇☆◻♢☆♋▂▋▲</dd>
|
||||
<br>
|
||||
<dt>peering</dt>
|
||||
<dd>just open a thread for now.</dd>
|
||||
<br>
|
||||
<dt>rules</dt>
|
||||
<dd>basically no stuff that will fuck with the functioning of the site.<br>
|
||||
- stuff that will get me in trouble like cp.<br>
|
||||
- flood/spam. duplicate posts may also get baleeted.
|
||||
</dd>
|
||||
<br>
|
||||
<dt>guidelines and things to keep in mind</dt>
|
||||
<dd>
|
||||
- i don't owe you shiieet. you don't owe me shieet.<br>
|
||||
- administration style: benevolent dictatorship.
|
||||
</dd>
|
||||
</dl>
|
||||
</body></html>
|
||||
7
contrib/static/chen-chan.css
Normal file
@@ -0,0 +1,7 @@
|
||||
body{font-family:monospace}
|
||||
dl{max-width:84ch}
|
||||
dd{margin-left:4ch;overflow:auto}
|
||||
.memearrows{color:green}
|
||||
pre{margin: 0 0 0 0}
|
||||
table,th,td{border:1px solid gray}
|
||||
table {border-collapse:collapse}
|
||||
BIN
contrib/static/clearnet.png
Normal file
|
After Width: | Height: | Size: 846 B |
21
contrib/static/dayman.css
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
dayman
|
||||
fighter of the night man
|
||||
champion of the sun
|
||||
*/
|
||||
|
||||
body {
|
||||
background-color: #FFEFC9;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: 100% 100%;
|
||||
background-image: url('maymface.png');
|
||||
}
|
||||
|
||||
.reply, .ukko_thread_header, th, .postform > tr , tbody > tr:nth-of-type( even ) {
|
||||
background: #FBFFC9;
|
||||
}
|
||||
|
||||
.navbar, table, thead, th, table, pre {
|
||||
background: #FFECBE;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="site.css"></link>
|
||||
<title> NNTPChan Frequently Asked Questions</title>
|
||||
<link rel="stylesheet" href="site.css" />
|
||||
<title> NNTPChan Frequently Asked Questions </title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>NNTPChan faq </h2>
|
||||
@@ -27,10 +27,19 @@
|
||||
<div>Question: How can I remove content from nntpchan completely? </div>
|
||||
<div>‾\(._.)/‾ I don't know. You probably can't unless every server agrees to remove the content, even then, nothing prevents someone from reposting it. You can't delete what you post on the internet.</div>
|
||||
</p>
|
||||
<p>
|
||||
<div>Question: Do you allow child porn? </div>
|
||||
<div>No, fuck off and die in a fire. All infringing posts are nuked.</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<div>Question: Do you allow XYZ content? </div>
|
||||
<div>If it violates USA Law or causes problems with my host, no. Otherwise, yes. <b>All posts on this site are the responsibility of the individual poster and not the administration of this server</b>.</div>
|
||||
<div>If it violates USA Law or causes problems with my host, no. Otherwise, probably.</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<div>Question: Someone posted something I don't like but it's not illegal</div>
|
||||
<div>That is not my problem. All posts on this site are the responsibility of the individual poster and not the administration of this server</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
@@ -39,9 +48,13 @@
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<div>Please send any questions to ampernand [|at\] gmail {dot} com with subject starting with "nntpchan question" </div>
|
||||
<div>Please send any gripes/questions/inqueries/suggestions/complaints to ampernand [|at\] gmail {dot} com with subject starting with "nntpchan question" </div>
|
||||
</p>
|
||||
<hr />
|
||||
</div>
|
||||
<audio autoplay="autoplay" loop="loop">
|
||||
<source src="about.mp3" type="audio/mpeg">
|
||||
<embed src="about.mp3">
|
||||
</audio>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
contrib/static/i2p.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
contrib/static/maymface.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
@@ -42,6 +42,76 @@ function nntpchan_unban() {
|
||||
})
|
||||
}
|
||||
|
||||
function get_board_target() {
|
||||
var e = document.getElementById("nntpchan_board_target");
|
||||
return e.value;
|
||||
}
|
||||
|
||||
function get_key_target() {
|
||||
var e = document.getElementById("nntpchan_key_target");
|
||||
return e.value;
|
||||
}
|
||||
|
||||
function nntpchan_key_del() {
|
||||
nntpchan_admin("pubkey.del", {
|
||||
pubkey: get_key_target()
|
||||
});
|
||||
}
|
||||
|
||||
function nntpchan_key_add() {
|
||||
nntpchan_admin("pubkey.add", {
|
||||
pubkey: get_key_target()
|
||||
});
|
||||
}
|
||||
|
||||
function get_nntp_username() {
|
||||
var e = document.getElementById("nntpchan_nntp_username");
|
||||
return e.value;
|
||||
}
|
||||
|
||||
function get_nntp_passwd() {
|
||||
var e = document.getElementById("nntpchan_nntp_passwd");
|
||||
return e.value;
|
||||
}
|
||||
|
||||
function nntpchan_admin_nntp(method) {
|
||||
nntpchan_admin(method, {
|
||||
username: get_nntp_username(),
|
||||
passwd: get_nntp_passwd()
|
||||
})
|
||||
}
|
||||
|
||||
function nntpchan_admin_board(method) {
|
||||
nntpchan_admin(method, {
|
||||
newsgroup: get_board_target()
|
||||
})
|
||||
}
|
||||
|
||||
function nntpchan_admin(method, param, handler_cb) {
|
||||
if (handler_cb) {
|
||||
// we got a handler already set
|
||||
} else {
|
||||
// no handler set
|
||||
var handler_cb = function(j) {
|
||||
if (j.result) {
|
||||
return document.createTextNode(j.result);
|
||||
} else {
|
||||
return "nothing happened?";
|
||||
}
|
||||
}
|
||||
}
|
||||
nntpchan_mod({
|
||||
name:"admin",
|
||||
parser: function(target) {
|
||||
return method;
|
||||
},
|
||||
handle: handler_cb,
|
||||
method: ( param && "POST" ) || "GET",
|
||||
data: param
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// handle delete command
|
||||
function nntpchan_delete() {
|
||||
nntpchan_mod({
|
||||
@@ -72,6 +142,81 @@ function nntpchan_delete() {
|
||||
});
|
||||
}
|
||||
|
||||
function createConnectionElement(j) {
|
||||
var e = document.createElement("div");
|
||||
e.setAttribute("class", "connection");
|
||||
var auth = document.createElement("div");
|
||||
auth.appendChild(document.createTextNode("Connection: "+j.name));
|
||||
// authentication state
|
||||
if (j.authed) {
|
||||
auth.setAttribute("class", "authed");
|
||||
auth.appendChild(document.createTextNode("(authenticated)"));
|
||||
} else {
|
||||
auth.appendChild(document.createTextNode("(not authenticated)"));
|
||||
}
|
||||
e.appendChild(auth);
|
||||
|
||||
// connection mode
|
||||
var mode = document.createElement("div");
|
||||
mode.setAttribute("class", "mode");
|
||||
mode.appendChild(document.createTextNode("mode: "+j.mode));
|
||||
e.appendChild(mode);
|
||||
|
||||
var pending = document.createElement("div");
|
||||
pending.setAttribute("class", "pending");
|
||||
// pending articles
|
||||
var articles = Object.keys(j.pending);
|
||||
pending.appendChild(document.createTextNode("pending articles: "+articles.length));
|
||||
for ( var idx = 0 ; idx < articles.length; idx ++ ) {
|
||||
var msgid = articles[idx];
|
||||
var state = j.pending[msgid];
|
||||
var elem = document.createElement("div");
|
||||
elem.appendChild(document.createTextNode(msgid + ": " + state));
|
||||
elem.setAttribute("class", "pending_item "+state);
|
||||
pending.appendChild(elem);
|
||||
}
|
||||
e.appendChild(pending);
|
||||
// e.appendChild(document.createTextNode(JSON.stringify(j)));
|
||||
return e;
|
||||
}
|
||||
|
||||
function inject_nntp_feed_element(feed, elem) {
|
||||
elem.appendChild(document.createElement("hr"));
|
||||
var name = document.createElement("div");
|
||||
name.setAttribute("class", "feeds_name");
|
||||
name_elem = document.createTextNode("Name: "+feed.State.Config.Name);
|
||||
name.appendChild(name_elem);
|
||||
elem.appendChild(name);
|
||||
var conns = document.createElement("div");
|
||||
conns.setAttribute("class", "connections");
|
||||
for ( var idx = 0 ; idx < feed.Conns.length; idx ++ ) {
|
||||
conns.appendChild(createConnectionElement(feed.Conns[idx]));
|
||||
}
|
||||
elem.appendChild(conns);
|
||||
}
|
||||
|
||||
function update_nntpchan_feed_ticker(elem) {
|
||||
nntpchan_admin("feed.list", null, function(j) {
|
||||
if (j) {
|
||||
if (j.error) {
|
||||
console.log("nntpchan_feed_ticker: error, "+j.error);
|
||||
} else {
|
||||
// remove all children
|
||||
while(elem.children.length) {
|
||||
elem.children[0].remove();
|
||||
}
|
||||
|
||||
var result = j.result;
|
||||
for (var idx = 0; idx < result.length; idx++) {
|
||||
var item = result[idx];
|
||||
var entry = document.createElement("div");
|
||||
inject_nntp_feed_element(item, entry);
|
||||
elem.appendChild(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function nntpchan_mod(mod_action) {
|
||||
|
||||
@@ -107,13 +252,7 @@ function nntpchan_mod(mod_action) {
|
||||
var result = mod_action.handle(j);
|
||||
if (result) {
|
||||
elem.appendChild(result);
|
||||
} else {
|
||||
// fail
|
||||
alert("mod action failed, handler returned nothing");
|
||||
}
|
||||
} else {
|
||||
// fail
|
||||
alert("mod action has no handler");
|
||||
}
|
||||
}
|
||||
} else if (status) {
|
||||
@@ -127,8 +266,14 @@ function nntpchan_mod(mod_action) {
|
||||
}
|
||||
if (mod_action.name) {
|
||||
var url = mod_action.name + "/" + target;
|
||||
ajax.open("GET", url);
|
||||
ajax.send();
|
||||
ajax.open(mod_action.method || "GET", url);
|
||||
var data = mod_action.data;
|
||||
if (data) {
|
||||
ajax.setRequestHeader("Content-type","text/json");
|
||||
ajax.send(JSON.stringify(data));
|
||||
} else {
|
||||
ajax.send();
|
||||
}
|
||||
} else {
|
||||
alert("mod action has no name");
|
||||
}
|
||||
|
||||
10
contrib/static/newboard.js
Normal file
@@ -0,0 +1,10 @@
|
||||
function createBoard() {
|
||||
var form = document.getElementById("postform");
|
||||
var e = document.getElementById("boardname");
|
||||
var board = e.value;
|
||||
if ( ! board.startsWith("overchan.") ) {
|
||||
board = "overchan." + board;
|
||||
}
|
||||
form.action = form.action + board;
|
||||
form.submit();
|
||||
}
|
||||
56
contrib/static/nntpchan.js
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// nntpchan.js -- frontend ui niceness
|
||||
//
|
||||
|
||||
|
||||
// insert a backlink for a post given its short hash
|
||||
function nntpchan_backlink(shorthash)
|
||||
{
|
||||
var elem = document.getElementById("postform_message");
|
||||
if ( elem )
|
||||
{
|
||||
elem.value += ">>" + shorthash.substr(0,10) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
var banner_count = 3;
|
||||
|
||||
// inject a banner into an element
|
||||
function nntpchan_inject_banners(elem, prefix) {
|
||||
var n = Math.floor(Math.random() * banner_count);
|
||||
var banner = prefix + "static/banner_"+n+".jpg";
|
||||
var e = document.createElement("img");
|
||||
e.src = banner;
|
||||
e.id = "nntpchan_banner";
|
||||
elem.appendChild(e);
|
||||
}
|
||||
|
||||
function get_storage() {
|
||||
var st = null;
|
||||
if (window.localStorage) {
|
||||
st = window.localStorage;
|
||||
} else if (localStorage) {
|
||||
st = localStorage;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
function enable_theme(prefix, name) {
|
||||
if (prefix && name) {
|
||||
var theme = document.getElementById("current_theme");
|
||||
if (theme) {
|
||||
theme.href = prefix + "static/"+ name + ".css";
|
||||
var st = get_storage();
|
||||
st.nntpchan_prefix = prefix;
|
||||
st.nntpchan_theme = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
// do other initialization here
|
||||
}
|
||||
|
||||
// apply themes
|
||||
var st = get_storage();
|
||||
enable_theme(st.nntpchan_prefix, st.nntpchan_theme);
|
||||
BIN
contrib/static/placeholder.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
@@ -1,20 +1,31 @@
|
||||
.thread {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 1em;
|
||||
display: inline-block;
|
||||
word-wrap: break-word;
|
||||
width: 100%;
|
||||
body {
|
||||
background: #EEF2FF url('bg.png') repeat-x 50% 0%;
|
||||
color: black;
|
||||
font-family: arial,helvetica,sans-serif;
|
||||
font-size: 10pt;
|
||||
margin: 0 4px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.frontend , .subject {
|
||||
color: #0f0d2d;
|
||||
|
||||
main,
|
||||
aside,
|
||||
section {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.frontend , .subject, .catalog_subject {
|
||||
color: #0F0C5D;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #117743;
|
||||
}
|
||||
|
||||
|
||||
.name , .subject {
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -24,14 +35,6 @@
|
||||
}
|
||||
|
||||
|
||||
input {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
input.button {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 350px;
|
||||
}
|
||||
@@ -44,8 +47,90 @@ textarea {
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
.reply, th, .ukko_thread_header {
|
||||
background: #d6daf0;
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
align: center;
|
||||
font-size: 13pt;
|
||||
background: #98E;
|
||||
color: black;
|
||||
display: inline-block;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
font-weight: bold;
|
||||
padding: 20px 20px 20px 20px;
|
||||
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: auto;
|
||||
}
|
||||
table.board-list-table {
|
||||
width: 100%;
|
||||
}
|
||||
table tbody td {
|
||||
margin: 0;
|
||||
padding: 4px 15px 4px 4px;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
table thead th {
|
||||
border: 1px solid #000333;
|
||||
padding: 4px 15px 5px 5px;
|
||||
|
||||
background: #98E;
|
||||
color: #000333;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
table tbody tr:nth-of-type( even ) {
|
||||
background-color: #D6DAF0;
|
||||
}
|
||||
|
||||
.postform >tr, th {
|
||||
background: #98E;
|
||||
font-size: 10pt;
|
||||
text-align: left;
|
||||
padding-right: 10px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
|
||||
#postform-inner tr {
|
||||
background-color: transparent!important;
|
||||
}
|
||||
|
||||
input[type="text"],input[type="password"],textarea {
|
||||
border: 1px solid #a9a9a9;
|
||||
text-indent: 0;
|
||||
text-shadow: none;
|
||||
text-transform: none;
|
||||
word-spacing: normal;
|
||||
font-size: inherit;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#board_td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.reply, .pagelist {
|
||||
background: #D6DAF0;
|
||||
border-width: 1px;
|
||||
border-style: none solid solid none;
|
||||
border-color: #B7C5D9;
|
||||
display: inline-block;
|
||||
max-width: 94%!important;
|
||||
}
|
||||
|
||||
.reply, .ukko_thread_header {
|
||||
background: #D6DAF0;
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
legend {
|
||||
/* background-color: #525252; */
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -53,19 +138,79 @@ hr {
|
||||
border-width: 1px medium medium;
|
||||
border-color: #b7c5d9;
|
||||
border-style: solid none none;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
a:hover , a:visited:hover {
|
||||
color: #f13333;
|
||||
.board_header {
|
||||
font-family: tahoma;
|
||||
letter-spacing: -2px;
|
||||
font-size: 20pt;
|
||||
margin: 0;
|
||||
color: #AF0A0F;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
.board_header_catalog {
|
||||
text-align: center;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #414383;
|
||||
.catalog_thread {
|
||||
display: inline-block;
|
||||
width: 180px;
|
||||
text-align: center;
|
||||
padding: 0.25em;
|
||||
height: 240px;
|
||||
overflow: hidden;
|
||||
background-color: rgba(182, 182, 182 ,0.12);
|
||||
margin: 0.1em;
|
||||
border: 2px solid rgba(111, 111, 111, 0.34);
|
||||
}
|
||||
|
||||
.catalog_thread:hover {
|
||||
background-color: #D6DAF0;
|
||||
}
|
||||
|
||||
#catalog_container {
|
||||
width: 95%;
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.catalog_header, .catalog_subject {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.linkThumb img {
|
||||
max-height: 128px;
|
||||
max-width: 128px;
|
||||
box-shadow: 0 0 4px rgba(0,0,0,0.55);
|
||||
border: 2px solid rgba(153,153,153,0);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
a:hover , a:visited:hover, .navbar-link > label:hover {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
a, a:visited, .navbar-link > label {
|
||||
color: #34345C;
|
||||
}
|
||||
|
||||
.postno {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.postno, .postnol, .postnol:visited {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.postno:hover, .postnol:hover, .postnol:visited:hover {
|
||||
color: #ff0000;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
@@ -75,73 +220,125 @@ a:visited {
|
||||
right: 0px;
|
||||
margin-top: 0px;
|
||||
z-index: 20;
|
||||
box-shadow: 0px 1px 20px rgba(0, 0, 0, 0.15);
|
||||
background: #CFD8EF;
|
||||
color: #616383;
|
||||
|
||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);
|
||||
border-bottom: 1px solid;
|
||||
background: #D6DAF0;
|
||||
color: #34345C;
|
||||
}
|
||||
|
||||
.navbar-sep {
|
||||
color: black;
|
||||
color: darkgray;
|
||||
}
|
||||
|
||||
.navbar-link > label {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#postform_container {
|
||||
margin-top: 5em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.navLinks {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.ukko_thread_header {
|
||||
padding: 5px 5px;
|
||||
margin: 5px 5px;
|
||||
float: left;
|
||||
clear: both;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: 10pt;
|
||||
padding-left: 10px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(to top, #eef2ff, #eaf1ff) repeat scroll;
|
||||
font-family: arial,helvetica,sans-serif;
|
||||
font-size: 10pt;
|
||||
margin: 0 4px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
|
||||
input, textarea {
|
||||
|
||||
}
|
||||
|
||||
.ukko_thread_header {
|
||||
border-color: #C0C3D4;
|
||||
border-top-left-radius: 0px;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.reply {
|
||||
margin-left: 1.8em;
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
|
||||
}
|
||||
|
||||
.frontend {
|
||||
margin-top: 0px;
|
||||
background: #e0f0f0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.op {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 1px;
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.post, .post_body {
|
||||
.post {
|
||||
margin-bottom: 5px;
|
||||
|
||||
min-width: 500px;
|
||||
}
|
||||
|
||||
.post_body > p {
|
||||
margin: 2px;
|
||||
.postheader {
|
||||
padding-top: 3px;
|
||||
padding-right: 5px
|
||||
}
|
||||
|
||||
.tripcode {
|
||||
color: #de04ef;
|
||||
}
|
||||
|
||||
@keyframes psych
|
||||
{
|
||||
0% {background-color: red; color: blue; }
|
||||
10% {background-color: yellow; color: red; }
|
||||
20% {background-color: blue; color: green; }
|
||||
30% {background-color: green; color: yellow; }
|
||||
40% {background-color: red; color: blue; }
|
||||
50% {background-color: yellow; color: green; }
|
||||
60% {background-color: blue; color: yellow; }
|
||||
70% {background-color: green; color: blue; }
|
||||
80% {background-color: red; color: green; }
|
||||
90% {background-color: yellow; color: red; }
|
||||
95% {background-color: blue; color: yellow; }
|
||||
100% {background-color: green; color: white; }
|
||||
}
|
||||
|
||||
.psy {
|
||||
animation: psych 2s linear infinite;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.memearrows {
|
||||
color: green;
|
||||
color: #789922;
|
||||
margin-left: none;
|
||||
}
|
||||
|
||||
.redtext {
|
||||
color: #AF0A0F;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
margin-left: none;
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.spoiler > p {
|
||||
background: black;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.spoiler:hover > p {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.intro {
|
||||
@@ -160,23 +357,118 @@ body {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
pre > p {
|
||||
margin: 0px 0px;
|
||||
.reply {
|
||||
padding: 3px 5px 3px 5px;
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.reply , .post_body > pre , .ukko_thread_header {
|
||||
padding: 7px 7px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 1px 1px 3px black;
|
||||
.post_body {
|
||||
margin-left: 15px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.post_body_line {
|
||||
margin-left: inherit;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.post_body > pre {
|
||||
background: #3f3f3f;
|
||||
color: #d17600;
|
||||
.post {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
.pagelist {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
margin-left: 15px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 50px;
|
||||
padding: 10px 10px 10px 10px;
|
||||
font-size: 12pt;
|
||||
font-weight: medium;
|
||||
|
||||
}
|
||||
|
||||
.backlink, .backlink:hover, .backlink:visited, .backlink:visited:hover {
|
||||
margin-left: none;
|
||||
color: #D00
|
||||
}
|
||||
|
||||
|
||||
.origin > img{
|
||||
height: 20px;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.postform_attachment {
|
||||
max-width: 330px;
|
||||
}
|
||||
|
||||
#faq > div {
|
||||
margin-left: 20%;
|
||||
width: 50%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#captcha_img {
|
||||
background: white;
|
||||
}
|
||||
|
||||
figure {
|
||||
float: left;
|
||||
margin: 1ex;
|
||||
}
|
||||
img.thumbnail {
|
||||
max-width: 350px;
|
||||
max-height: 350px;
|
||||
}
|
||||
|
||||
|
||||
.replybar {
|
||||
float: left;
|
||||
position: fixed;
|
||||
top: 2ex;
|
||||
right: 0;
|
||||
width: 34%
|
||||
}
|
||||
@media (max-width: 100ex) {
|
||||
.replybar {
|
||||
width: 100%;
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-reply:checked ~ div {
|
||||
width: 100%;
|
||||
position: static;
|
||||
}
|
||||
|
||||
textarea#reply-text {
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.hide-reply {
|
||||
float: right;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#nntpchan_banner {
|
||||
align: center;
|
||||
}
|
||||
|
||||
.legal {
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.attachments {
|
||||
float: left;
|
||||
}
|
||||
BIN
contrib/static/tor.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,3 @@
|
||||
/*
|
||||
put your custom stylesheet here
|
||||
*/
|
||||
27
contrib/templates/chen-chan/board.mustache
Normal file
@@ -0,0 +1,27 @@
|
||||
{{!
|
||||
board.mustache, displays the contents of page N of the board
|
||||
|
||||
template parameters:
|
||||
- board ( the model of the current page )
|
||||
- page ( the page number of the current page )
|
||||
|
||||
board has the properties:
|
||||
- Prefix ( absolute path like //site.tld/ or /path/ )
|
||||
- Board ( the name of the board )
|
||||
- Navbar ( a function that renders the navbar, should not be escaped )
|
||||
- Threads ( a list of Thread Models with the last few replies )
|
||||
}}
|
||||
<!doctype html><html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>{{board.Board}}</title></head><body>
|
||||
{{{board.Navbar}}}
|
||||
{{{form}}}
|
||||
<dl>
|
||||
<hr>
|
||||
{{#board.Threads}}
|
||||
{{{OP.Truncate.RenderPost}}}
|
||||
{{#Truncate.Replies}}
|
||||
{{{Truncate.RenderPost}}}
|
||||
{{/Truncate.Replies}}
|
||||
<hr>
|
||||
{{/board.Threads}}
|
||||
</dl>
|
||||
</body></html>
|
||||
33
contrib/templates/chen-chan/boardlist.mustache
Normal file
@@ -0,0 +1,33 @@
|
||||
{{!
|
||||
boardlist.mustache -- full list of every board
|
||||
template parameters:
|
||||
- graph ( a list of 4 string tuples: (board, posts_per_hour, posts_per_day, total_posts) )
|
||||
- frontend ( the name of the frontend )
|
||||
- prefix ( the site's prefix )
|
||||
}}
|
||||
<!doctype html><html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>{{frontend}} boards</title></head><body>
|
||||
<table>
|
||||
<tr>
|
||||
<th>board</th>
|
||||
<th>posts per hour</th>
|
||||
<th>posts per day</th>
|
||||
<th>total</th>
|
||||
</tr>
|
||||
{{# graph}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{prefix}}{{Board}}-0.html">{{Board}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{Hour}}
|
||||
</td>
|
||||
<td>
|
||||
{{Day}}
|
||||
</td>
|
||||
<td>
|
||||
{{All}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/ graph}}
|
||||
</table>
|
||||
</body></html>
|
||||
11
contrib/templates/chen-chan/frontpage.mustache
Normal file
@@ -0,0 +1,11 @@
|
||||
{{!
|
||||
frontpage.mustache -- template for index.html
|
||||
template parameters:
|
||||
- boardgraph ( a boardPageRows instance, see srnd/model.go )
|
||||
- postgraph ( a postsGraph instance , see srnd/model.go )
|
||||
- overview ( an overviewModel instance, see srnd/model.go )
|
||||
- totalposts ( the number of total posts we have ever seen )
|
||||
- frontend ( the name of the frontend )
|
||||
- prefix ( the site's prefix )
|
||||
}}
|
||||
<!doctype html><html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>{{frontend}} on nntpchan</title></head><body><p>{{frontend}} on nntpchan</p><p><a href="ukko.html">overboard</a> <a href="{{prefix}}boards.html">boards</a> <a href="{{prefix}}static/chen-chan-faq.html">faq</a></p><dl><dt>last posts:</dt><dd>{{{overview.Render}}}</dd></dl><dl><dt>board stats:</dt><dd><table><tr><th>board</th><th>posts this hour</th><th>posts today</th><th>total</th></tr>{{# boardgraph}}<tr><td><a href="{{prefix}}{{Board}}-0.html">{{Board}}</a></td><td>{{Hour}}</td><td>{{Day}}</td><td>{{All}}</td></tr>{{/ boardgraph}}</table></dd></dl><dl><dt>total stats:</dt><dd>{{{postsgraph.Render}}}</dd></dl><p>{{totalposts}} posts total since 2015-12-23</p></body></html>
|
||||
36
contrib/templates/chen-chan/graph_history.mustache
Normal file
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
graph_history.mustache
|
||||
template parameters:
|
||||
- history ( a list of PostEntry instances, see srnd/model.go )
|
||||
|
||||
}}
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"></meta>
|
||||
<link rel="stylesheet" href="{{prefix}}site.css" />
|
||||
<link rel="stylesheet" href="{{prefix}}user.css" />
|
||||
<title> Post History</title>
|
||||
</head>
|
||||
<body>
|
||||
<td>
|
||||
<table id="history_graph">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Month</th>
|
||||
<th>Posts</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#history.Scale}}
|
||||
<tr>
|
||||
<td>{{Date}}</td>
|
||||
<td class="history_num">{{Num}}</td>
|
||||
<td>{{OvercockGraph}}</td>
|
||||
</tr>
|
||||
{{/history.Scale}}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</body>
|
||||
</html>
|
||||
15
contrib/templates/chen-chan/keygen.mustache
Normal file
@@ -0,0 +1,15 @@
|
||||
{{!
|
||||
keygen.mustache -- page containing a newly generated tripcode
|
||||
template parameters:
|
||||
- prefix ( the site prefix )
|
||||
- public ( the public key in hex )
|
||||
- secret ( the secret key in hex )
|
||||
- tripcode ( html version of the public key )
|
||||
}}
|
||||
<!doctype html><html><head><title>new tripcode</title></head><body><pre>
|
||||
new tripcode
|
||||
|
||||
secret: {{secret}}
|
||||
public: {{public}}
|
||||
tripcode: {{{tripcode}}}
|
||||
</pre></body></html>
|
||||
7
contrib/templates/chen-chan/modlogin.mustache
Normal file
@@ -0,0 +1,7 @@
|
||||
<!doctype html><html><head><link rel="stylesheet" href="{{prefix}}static/chen-chan.css"><title>login</title></head><body>
|
||||
<form action="login" method="POST" name="modlogin">
|
||||
<label for="mod_key">secret</label>
|
||||
<input type="password" id="mod_key" name="privkey">
|
||||
<input type="submit" value="login">
|
||||
</form>
|
||||
</body></html>
|
||||
9
contrib/templates/chen-chan/modlogin_result.mustache
Normal file
@@ -0,0 +1,9 @@
|
||||
{{!
|
||||
modlogin_result.mustache -- shows the result of a login attempt
|
||||
template parameters:
|
||||
- prefix ( the site prefix )
|
||||
- mod_prefix ( the prefix to the mod panel, could be something like https://mod.site.tld/ or /mod/ )
|
||||
- message ( the message returned from the login attempt )
|
||||
- fail ( present if the login failed ) // not yet added
|
||||
}}
|
||||
<!doctype html><html><head><meta http-equiv="refresh" content="1; {{mod_prefix}}"><title>login</title></head><body><p>{{message}}</p></body></html>
|
||||
79
contrib/templates/chen-chan/modpage.mustache
Normal file
@@ -0,0 +1,79 @@
|
||||
{{!
|
||||
modpage.mustache -- the moderator panel when logged in
|
||||
template parameters:
|
||||
- prefix ( the site's prefix )
|
||||
}}
|
||||
<!doctype html><html><head>
|
||||
<link rel="stylesheet" href="{{prefix}}static/chen-chan.css">
|
||||
<!-- yes it uses js -->
|
||||
<script src="{{prefix}}static/mod.js"></script>
|
||||
<title>nntpchan mod page</title>
|
||||
</head><body>
|
||||
<dl>
|
||||
<dt>post actions</dt>
|
||||
<dd>
|
||||
<div>
|
||||
<label for="nntpchan_mod_target">target</label>
|
||||
<input id="nntpchan_mod_target" type="text">
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_ban()">ban (url)</button>
|
||||
<button onclick="nntpchan_delete()">delete (url)</button>
|
||||
<button onclick="nntpchan_unban()">unban (ip)</button>
|
||||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>key actions</dt>
|
||||
<dd>
|
||||
<div>
|
||||
<label for="nntpchan_board_target">pubkey:</label>
|
||||
<input type="text" id="nntpchan_key_target" />
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_key_add()">add key</button>
|
||||
<button onclick="nntpchan_key_del()">remove key</button>
|
||||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>board actions</dt>
|
||||
<dd>
|
||||
<div>
|
||||
<label for="nntpchan_board_target">board name:</label>
|
||||
<input type="text" id="nntpchan_board_target">
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_board('frontend.add')">add board</button>
|
||||
<button onclick="nntpchan_admin_board('frontend.regen')">regenerate</button>
|
||||
<button onclick="nntpchan_admin_board('frontend.ban')">ban</button>
|
||||
<button onclick="nntpchan_admin_board('frontend.unban')">unban</button>
|
||||
<button onclick="nntpchan_admin_board('frontend.nuke')">nuke</button>
|
||||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>lightweight actions</dt>
|
||||
<dd>
|
||||
<button onclick="nntpchan_admin('template.reload')">reload all templates</button>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>very load heavy actions, use with care</dt>
|
||||
<dd>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin('frontend.regen')">regenerate all pages</button>
|
||||
<button onclick="nntpchan_admin('thumbnail.regen')">regenerate all thumbnails</button>
|
||||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>status</dt>
|
||||
<dd>
|
||||
<div id="nntpchan_mod_result"></div>
|
||||
<noscript>
|
||||
<b>enable js to use the mod panel kthx</b>
|
||||
</noscript>
|
||||
</dd>
|
||||
</dl>
|
||||
</body></html>
|
||||
12
contrib/templates/chen-chan/navbar.mustache
Normal file
@@ -0,0 +1,12 @@
|
||||
{{!
|
||||
navbar.mustache -- element on the top of each nod-mod page
|
||||
|
||||
TODO: make this not suck, have a board list, have board page list
|
||||
|
||||
template parameters:
|
||||
- name ( the name of whatever resource we are on, board/thread )
|
||||
- frontend ( the name of the frontend we are on )
|
||||
- links ( a list of Link Models to display )
|
||||
- prefix ( site prefix )
|
||||
}}
|
||||
<p>{{name}} on {{frontend}} | {{# links}} <a href="{{LinkURL}}">{{Text}}</a> {{/ links}} | <a href="{{prefix}}">front page</a> <a href="{{prefix}}ukko.html">overboard</a></p>
|
||||
1
contrib/templates/chen-chan/newboard.mustache
Normal file
@@ -0,0 +1 @@
|
||||
no apparently.
|
||||
7
contrib/templates/chen-chan/overview.mustache
Normal file
@@ -0,0 +1,7 @@
|
||||
{{! overview.mustache
|
||||
paramters:
|
||||
|
||||
- overview (list of PostModels in order of last posted)
|
||||
|
||||
}}
|
||||
<table><tr><th>date</th><th>board</th><th>subject</th></tr>{{#overview}}<tr><td>{{Date}}</td><td><a href="{{Prefix}}{{Board}}-0.html">{{Board}}</a></td><td><a href="{{PostURL}}">{{Truncate.Subject}}</a></td></tr>{{/overview}}</table>
|
||||
15
contrib/templates/chen-chan/post.mustache
Normal file
@@ -0,0 +1,15 @@
|
||||
<dt id="{{PostHash}}">
|
||||
<a onclick="nntpchan_backlink('{{ShortHash}}');" title="{{MessageID}}">{{ShortHash}}</a>
|
||||
{{Date}}
|
||||
{{#IsI2P}}i2p{{/IsI2P}}{{#IsTor}}tor{{/IsTor}}{{#IsClearnet}}clr{{/IsClearnet}}
|
||||
{{Subject}}
|
||||
{{Name}}
|
||||
{{{Pubkey}}}
|
||||
<a href="{{PostURL}}">[reply]</a>
|
||||
</dt>
|
||||
<dd>
|
||||
{{{RenderBody}}}
|
||||
{{#Attachments}}
|
||||
file: <a href="{{Source}}" target="_blank">{{Filename}}</a><br><br>
|
||||
{{/Attachments}}
|
||||
</dd>
|
||||
3
contrib/templates/chen-chan/post_fail.mustache
Normal file
@@ -0,0 +1,3 @@
|
||||
<!doctype html><html><head>
|
||||
<meta http-equiv="refresh" content="1; {{redirect_url}}"></head>
|
||||
<body><p>fail: {{reason}}</p></body></html>
|
||||
40
contrib/templates/chen-chan/post_retry.mustache
Normal file
@@ -0,0 +1,40 @@
|
||||
<html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>try again</title></head><body>
|
||||
<form enctype="multipart/form-data" name="post" method="post">
|
||||
{{#attachment}}
|
||||
<input type="hidden" name="attachment_data" value="{{attachment}}">
|
||||
<input type="hidden" name="attachment_filename" value="{{attachment_filename}}">
|
||||
<input type="hidden" name="attachment_mime" value="{{attachment_type}}">
|
||||
{{/attachment}}
|
||||
<input type="hidden" name="reference" value="{{reference}}">
|
||||
<input type="hidden" name="name" value="{{name}}">
|
||||
<input type="hidden" name="subject" value="{{subject}}">
|
||||
<input type="hidden" name="captcha_id" value="{{captcha_id}}">
|
||||
<input type="hidden" name="message" value="{{message}}">
|
||||
<div id="postform-outer">
|
||||
<div id="postform-inner">
|
||||
<div>{{fail_message}}</div>
|
||||
<table class="postform">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
Captcha
|
||||
</th>
|
||||
<td>
|
||||
<img id="captcha_img" src="{{prefix}}captcha/{{captcha_id}}.png" alt="captcha" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Solution
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="captcha" />
|
||||
<input type="submit" value="Post" class="button" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body></html>
|
||||
7
contrib/templates/chen-chan/post_success.mustache
Normal file
@@ -0,0 +1,7 @@
|
||||
{{!
|
||||
post_success.mustache -- shown when we do a successful post
|
||||
template parameters:
|
||||
- redirect_url ( the url of the next page we should redirect to )
|
||||
- message_id ( the value of the Message-ID header in the post we made, the truncated sha1 of this is the >>posthash )
|
||||
}}
|
||||
<!doctype html><html><head><meta http-equiv="refresh" content="2; {{redirect_url}}"></head><body><pre>posted as {{message_id}}</pre></body></html>
|
||||
20
contrib/templates/chen-chan/postform.mustache
Normal file
@@ -0,0 +1,20 @@
|
||||
{{!
|
||||
postform.mustache -- the form for posting
|
||||
|
||||
template parameters:
|
||||
- post_url ( the url of the post form )
|
||||
- reference ( the post we are replying to, or empty string if it's an op )
|
||||
- button ( the text for the reply button )
|
||||
}}
|
||||
<form action="{{post_url}}" enctype="multipart/form-data" name="post" method="post" style="overflow:auto">
|
||||
<input type="hidden" name="reference" value="{{reference}}">
|
||||
<textarea id="postform_message" name="message" placeholder="text" cols="40" rows="10" style="float:left" ></textarea><br>
|
||||
<div style="float:left">
|
||||
<input type="file" name="attachment"><br>
|
||||
<input type="text" name="subject" placeholder="subject"><br>
|
||||
<input type="text" name="name" placeholder="name"><br>
|
||||
<input type="text" name="captcha" placeholder="captcha"><br>
|
||||
<input type="submit" value="{{button}}" class="button"><br>
|
||||
</div>
|
||||
<img id="captcha_img" src="{{prefix}}captcha/img" alt="captcha" style="float:left">
|
||||
</form>
|
||||
7
contrib/templates/chen-chan/posts_graph.mustache
Normal file
@@ -0,0 +1,7 @@
|
||||
{{!
|
||||
posts graph.mustache -- post frequence graph
|
||||
parameters:
|
||||
|
||||
* graph - a postsGraph instance (see srnd/model.go)
|
||||
}}
|
||||
<table><tr><th>date</th><th>posts</th><th>cock</th></tr>{{#graph.Scale}}<tr><td>{{Day}}</td><td>{{Num}}</td><td>{{OvercockGraph}}</td></tr>{{/graph.Scale}}</table>
|
||||
23
contrib/templates/chen-chan/thread.mustache
Normal file
@@ -0,0 +1,23 @@
|
||||
{{!
|
||||
thread.mustache -- renders to a thread-*.html page, shows the entire thread
|
||||
template parameters:
|
||||
- board ( the Board Model of the board this thread was posted in )
|
||||
- thread ( the Thread Model of the current thread being rendered )
|
||||
- form ( the post form markup )
|
||||
|
||||
Thread Model attributes:
|
||||
- OP , the Post Model of the original poster
|
||||
- Replies , a list of all the replies or empty if none
|
||||
- Board , the name of the Board this thread is on
|
||||
- BoardURL , the url that points to the board index page
|
||||
}}
|
||||
<!doctype html><html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>{{thread.OP.Subject}}</title><script src="{{thread.Prefix}}static/nntpchan.js"></script></head><body>
|
||||
{{{thread.Navbar}}}
|
||||
{{{form}}}
|
||||
<dl>
|
||||
{{{thread.OP.RenderPost}}}
|
||||
{{# thread.Replies}}
|
||||
{{{RenderPost}}}
|
||||
{{/ thread.Replies}}
|
||||
</dl>
|
||||
</body></html>
|
||||
19
contrib/templates/chen-chan/ukko.mustache
Normal file
@@ -0,0 +1,19 @@
|
||||
{{!
|
||||
ukko.mustache -- overboard, contains the last threads posted regardless of newsgroup
|
||||
template parameters:
|
||||
- prefix ( site prefix )
|
||||
- threads ( a list of Thread Models that represent the latest threads )
|
||||
}}
|
||||
<!doctype html><html><head><link rel="stylesheet" href="/static/chen-chan.css"><title>ukko/overboard</title></head><body>
|
||||
<a href="/">frontpage</a>
|
||||
{{#threads}}
|
||||
<hr>
|
||||
<p>posted on <a href="{{{BoardURL}}}">{{OP.Board}}</a></p>
|
||||
<dl>
|
||||
{{{OP.Truncate.RenderPost}}}
|
||||
{{#Truncate.Replies}}
|
||||
{{{Truncate.RenderPost}}}
|
||||
{{/Truncate.Replies}}
|
||||
</dl>
|
||||
{{/threads}}
|
||||
</body></html>
|
||||
25
contrib/templates/default/404.mustache
Normal file
@@ -0,0 +1,25 @@
|
||||
{{!
|
||||
404.mustache -- 404 page
|
||||
template parameters:
|
||||
- prefix (the site prefix)
|
||||
}}
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title> 404 </title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{prefix}}static/nntpchan.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<div class="not_found">
|
||||
<img src="{{prefix}}static/404.png"></img>
|
||||
<div class="not_found_message">
|
||||
{{#i18n.Translations}}{{resource_not_found}}{{/i18n.Translations}}
|
||||
</div>
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
@@ -14,14 +14,22 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{board.Prefix}}static/site.css"></link>
|
||||
<meta name="viewport" content="initial-scale=1" />
|
||||
<link rel="stylesheet" href="{{board.Prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{board.Prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{board.Prefix}}static/nntpchan.js"></script>
|
||||
<title>{{board.Board}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<body onload="main()">
|
||||
<!-- begin navbar -->
|
||||
{{{board.Navbar}}}
|
||||
<!-- end navbar -->
|
||||
|
||||
<center>
|
||||
<div id="nntpchan_banner">
|
||||
</div>
|
||||
</center>
|
||||
<div class="board_header">{{board.Board}}</div>
|
||||
<div class="board_header_catalog"><a href="{{board.Prefix}}catalog-{{board.Name}}.html"> {{#i18n.Translations}}{{catalog_label}}{{/i18n.Translations}} </a></div>
|
||||
<!-- postform -->
|
||||
<div id="postform_container">
|
||||
{{{form}}}
|
||||
@@ -30,17 +38,32 @@
|
||||
<div id="threads_container">
|
||||
{{#board.Threads}}
|
||||
<div class="thread" id="thread_{{OP.PostHash}}">
|
||||
<div clsss="thread_header">
|
||||
<div class="thread_header">
|
||||
</div>
|
||||
{{{OP.Truncate.RenderPost}}}
|
||||
{{#Truncate.Replies}}
|
||||
{{{Truncate.RenderPost}}}
|
||||
<br />
|
||||
{{/Truncate.Replies}}
|
||||
<hr />
|
||||
</div>
|
||||
<br/>
|
||||
<hr/>
|
||||
{{/board.Threads}}
|
||||
</div>
|
||||
<div class="pagelist">{{# board.PageList }}[<a href="{{LinkURL}}"> {{Text}} </a>] {{/ board.PageList }}
|
||||
<span class="navbar-sep">
|
||||
|
|
||||
</span>
|
||||
<a href="{{board.Prefix}}catalog-{{board.Name}}.html"> {{#i18n.Translations}}{{catalog_label}}{{/i18n.Translations}} </a>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, "{{board.Prefix}}");
|
||||
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p class="legal">All posts on this site are the responsibility of the individual poster and not the administration, pursuant to 47 U.S.C. § 230.</p>
|
||||
<p class="legal">To make a DMCA request or report illegal content, please contact the administration</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
51
contrib/templates/default/boardlist.mustache
Normal file
@@ -0,0 +1,51 @@
|
||||
{{!
|
||||
boardlist.mustache -- full list of every board
|
||||
template parameters:
|
||||
- graph ( a list of 4 string tuples: (board, posts_per_hour, posts_per_day, total_posts) )
|
||||
- frontend ( the name of the frontend )
|
||||
- prefix ( the site's prefix )
|
||||
}}
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<link rel="stylesheet" href="{{prefix}}static/user.css"></link>
|
||||
<title> {{frontend}} {{#i18n.Translations}}{{board_list_title}}{{/i18n.Translations}} </title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<div class="index-outer">
|
||||
<div class="index-inner">
|
||||
<table id="board_graph">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> {{#i18n.Translations}}{{board_label}}{{/i18n.Translations}} </th>
|
||||
<th> {{#i18n.Translations}}{{pph_label}}{{/i18n.Translations}} </th>
|
||||
<th> {{#i18n.Translations}}{{ppd_label}}{{/i18n.Translations}} </th>
|
||||
<th> {{#i18n.Translations}}{{total}}{{/i18n.Translations}} </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{# graph}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{prefix}}{{Board}}-0.html">{{Board}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{Hour}}
|
||||
</td>
|
||||
<td>
|
||||
{{Day}}
|
||||
</td>
|
||||
<td>
|
||||
{{All}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/ graph}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
45
contrib/templates/default/catalog.mustache
Normal file
@@ -0,0 +1,45 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="initial-scale=1" />
|
||||
<link rel="stylesheet" href="{{board.Prefix}}static/site.css" />
|
||||
<link rel="stylesheet" href="{{board.Prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{board.Prefix}}static/nntpchan.js"></script>
|
||||
<title>{{#i18n.Translations}}{{catalog_title}}{{/i18n.Translations}} {{board.Name}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- begin navbar -->
|
||||
{{{board.Navbar}}}
|
||||
<!-- end navbar -->
|
||||
<center>
|
||||
<div id="nntpchan_banner">
|
||||
</div>
|
||||
</center>
|
||||
<div class="board_header">{{#i18n.Translations}}{{catalog_title}}{{/i18n.Translations}} {{board.Name}}</div>
|
||||
<!-- postform -->
|
||||
<hr />
|
||||
<div id="catalog_container">
|
||||
{{#board.Threads}}
|
||||
<div class="catalog_thread">
|
||||
<a class="linkThumb" href="{{OP.PostURL}}"><img src="{{OP.RepresentativeThumb}}"></a>
|
||||
<div class="catalog_header">{{#i18n.Translations}}{{replies_short_label}}{{/i18n.Translations}}: {{ReplyCount}} / {{#i18n.Translations}}{{pictures_short_label}}{{/i18n.Translations}}: {{Page}}</div>
|
||||
<div class="catalog_subject">{{OP.Subject}}</div>
|
||||
<div class="catalog_body">
|
||||
{{{OP.RenderBody}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/board.Threads}}
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, "{{board.Prefix}}");
|
||||
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p class="legal">All posts on this site are the responsibility of the individual poster and not the administration, pursuant to 47 U.S.C. § 230.</p>
|
||||
<p class="legal">To make a DMCA request or report illegal content, please contact the administration</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +1,9 @@
|
||||
{{!
|
||||
frontpage.mustache -- template for index.html
|
||||
template parameters:
|
||||
- graph ( a list of 4 string tuples: (board, posts_per_hour, posts_per_day, total_posts) )
|
||||
- boardgraph ( markup of boardPageRows instance, see srnd/model.go )
|
||||
- postgraph ( markup of postsGraph instance , see srnd/model.go )
|
||||
- overview ( markup of overviewModel instance , see srnd/model.go )
|
||||
- totalposts ( the number of total posts we have ever seen )
|
||||
- frontend ( the name of the frontend )
|
||||
- prefix ( the site's prefix )
|
||||
@@ -9,49 +11,80 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script src="{{prefix}}static/nntpchan.js" type="text/javascript"></script>
|
||||
<title> {{frontend}} on nntpchan </title>
|
||||
</head>
|
||||
<body>
|
||||
<body onload="main()">
|
||||
{{{navbar}}}
|
||||
<center>
|
||||
<div class="index-outer">
|
||||
<div class="index-inner">
|
||||
<h1> {{frontend}} on nntpchan </h1>
|
||||
<h2>View the <a href="ukko.html">overboard</a></h2>
|
||||
<h3>Read the <a href="{{prefix}}static/faq.html">FAQ</a></h3>
|
||||
<h3>Join the <a href="https://i2p.rocks/irc/?channels=overchan&nick=nameless">IRC</a></h3>
|
||||
<h3>Join the IRC on <a href="https://qchat.rizon.net/?channels=#nntpchan">rizon</a> or <a href="irc://127.0.0.1:6668/overchan">irc2p</a></h3>
|
||||
<h3>Lurk on <a href="irc://allyour4nert7pkh.onion/overchan">URC</a></h3>
|
||||
<h3>Check out the <a href="{{prefix}}boards.html">board list</a></h3>
|
||||
<h3>Fork on github: <a href="https://github.com/majestrate/nntpchan/">frontend</a> and <a href="https://github.com/majestrate/srndv2/">core</a></h3>
|
||||
<h4>We've Had {{totalposts}} Posts Since August 01 2015 </h4>
|
||||
</div>
|
||||
<div id="nntpchan_banner">
|
||||
</div>
|
||||
<div class="index-inner">
|
||||
<table id="board_graph">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th> Board </th>
|
||||
<th> Post per Hour </th>
|
||||
<th> Post per Day </th>
|
||||
<th> Total </th>
|
||||
</tr>
|
||||
{{# graph}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{prefix}}{{Board}}-0.html">{{Board}}</a>
|
||||
<td class="posts_td">
|
||||
{{{postsgraph}}}
|
||||
</td>
|
||||
<td>
|
||||
{{Hour}}
|
||||
</td>
|
||||
<td>
|
||||
{{Day}}
|
||||
</td>
|
||||
<td>
|
||||
{{All}}
|
||||
<td class="board_td">
|
||||
{{! todo: move boardgraph into its own file like postsgraph }}
|
||||
<table id="board_graph">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> {{#i18n.Translations}}{{board_label}}{{/i18n.Translations}} </th>
|
||||
<th> {{#i18n.Translations}}{{posts_hour}}{{/i18n.Translations}} </th>
|
||||
<th> {{#i18n.Translations}}{{posts_today}}{{/i18n.Translations}} </th>
|
||||
<th> {{#i18n.Translations}}{{total}}{{/i18n.Translations}} </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{# boardgraph}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{prefix}}{{Board}}-0.html">{{Board}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{Hour}}
|
||||
</td>
|
||||
<td>
|
||||
{{Day}}
|
||||
</td>
|
||||
<td>
|
||||
{{All}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/ boardgraph}}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
{{/ graph}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{{overview}}}
|
||||
</div>
|
||||
</div>
|
||||
</center>
|
||||
<script type="text/javascript">
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, "{{prefix}}");
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p class="legal">All posts on this site are the responsibility of the individual poster and not the administration, pursuant to 47 U.S.C. § 230.</p>
|
||||
<p class="legal">To make a DMCA request or report illegal content, please contact the administration</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
36
contrib/templates/default/graph_history.mustache
Normal file
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
graph_history.mustache
|
||||
template parameters:
|
||||
- history ( a list of PostEntry instances, see srnd/model.go )
|
||||
|
||||
}}
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"></meta>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<title>{{#i18n.Translations}}{{post_history_title}}{{/i18n.Translations}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<td>
|
||||
<table id="history_graph">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{#i18n.Translations}}{{month}}{{/i18n.Translations}}</th>
|
||||
<th>{{#i18n.Translations}}{{posts}}{{/i18n.Translations}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#history.Scale}}
|
||||
<tr>
|
||||
<td>{{Date}}</td>
|
||||
<td class="history_num">{{Num}}</td>
|
||||
<td>{{OvercockGraph}}</td>
|
||||
</tr>
|
||||
{{/history.Scale}}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,12 +9,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"></meta>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<title> here is a new tripcode </title>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{prefix}}static/nntpchan.js"></script>
|
||||
<title>{{#i18n.Translations}}{{new_tripcode_title}}{{/i18n.Translations}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre>New Tripcode:
|
||||
<div id="secret_key">secret: {{secret}}</div><div id="public_key">public: {{public}}</div><div>tripcode: <span class="tripcode" id="capcode_key">{{{tripcode}}}</span></div>
|
||||
<pre>{{#i18n.Translations}}{{new_tripcode_label}}{{/i18n.Translations}}:
|
||||
<div id="secret_key">{{#i18n.Translations}}{{secret_key}}{{/i18n.Translations}}: {{secret}}</div><div id="public_key">{{#i18n.Translations}}{{public_key}}{{/i18n.Translations}}: {{public}}</div><div>{{#i18n.Translations}}{{tripcode}}{{/i18n.Translations}}: <span class="tripcode" id="capcode_key">{{{tripcode}}}</span></div>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<link ref="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<title>login</title>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<title>{{#i18n.Translations}}{{login}}{{/i18n.Translations}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="login" method="POST" name="modlogin">
|
||||
<label for="mod_key">secret</label>
|
||||
<label for="mod_key">{{#i18n.Translations}}{{secret_key}}{{/i18n.Translations}}</label>
|
||||
<input type="password" id="mod_key" name="privkey" />
|
||||
<input type="submit" value="login" />
|
||||
<input type="submit" value="{{#i18n.Translations}}{{login}}{{/i18n.Translations}}" />
|
||||
{{{csrfField}}}
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
- prefix ( the site prefix )
|
||||
- mod_prefix ( the prefix to the mod panel, could be something like https://mod.site.tld/ or /mod/ )
|
||||
- message ( the message returned from the login attempt )
|
||||
- fail ( present if the login failed )
|
||||
- fail ( present if the login failed ) // not yet added
|
||||
}}
|
||||
<html>
|
||||
<head>
|
||||
<link ref="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<meta http-equiv="refresh" content="1; {{mod_prefix}}"></meta>
|
||||
<title>login</title>
|
||||
<title>{{#i18n.Translations}}{{login}}{{/i18n.Translations}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>{{message}}</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -6,28 +6,110 @@
|
||||
}}
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<!-- yes it uses js -->
|
||||
<script type="text/javascript" src="{{prefix}}static/nntpchan.js"></script>
|
||||
<script type="text/javascript" src="{{prefix}}static/mod.js"></script>
|
||||
<title> nntpchan mod page </title>
|
||||
<title> {{#i18n.Translations}}{{modpage_title}}{{/i18n.Translations}} </title>
|
||||
</head>
|
||||
<body>
|
||||
<body onload="main()">
|
||||
<div>
|
||||
<div> post actions </div>
|
||||
<div> {{#i18n.Translations}}{{post_actions_label}}{{/i18n.Translations}} </div>
|
||||
<hr />
|
||||
<div>
|
||||
<label for="nntpchan_mod_target">target</label>
|
||||
<label for="nntpchan_mod_target">{{#i18n.Translations}}{{target_label}}{{/i18n.Translations}}</label>
|
||||
<input id="nntpchan_mod_target" type="text" />
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_ban()">ban (url)</button>
|
||||
<button onclick="nntpchan_delete()">delete (url)</button>
|
||||
<button onclick="nntpchan_unban()">unban (ip)</button>
|
||||
<button onclick="nntpchan_ban()">{{#i18n.Translations}}{{ban_url_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_delete()">{{#i18n.Translations}}{{delete_url_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_unban()">{{#i18n.Translations}}{{unban_ip_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<div> {{#i18n.Translations}}{{key_actions_label}}{{/i18n.Translations}} </div>
|
||||
<div>
|
||||
<label for="nntpchan_board_target">{{#i18n.Translations}}{{pubkey_label}}{{/i18n.Translations}}:</label>
|
||||
<input type="text" id="nntpchan_key_target" />
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_key_add()">{{#i18n.Translations}}{{add_key_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_key_del()">{{#i18n.Translations}}{{remove_key_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<div> {{#i18n.Translations}}{{nntp_login_label}}{{/i18n.Translations}} </div>
|
||||
<div>
|
||||
<label for="nntpchan_nntp_username">{{#i18n.Translations}}{{username}}{{/i18n.Translations}}:</label>
|
||||
<input id="nntpchan_nntp_username" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="nntpchan_nntp_passwd">{{#i18n.Translations}}{{password}}{{/i18n.Translations}}:</label>
|
||||
<input type="password" id="nntpchan_nntp_passwd" />
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_nntp('nntp.login.add')">{{#i18n.Translations}}{{add_user_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_nntp('nntp.login.del')">{{#i18n.Translations}}{{remove_user_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<div> {{#i18n.Translations}}{{board_actions_label}}{{/i18n.Translations}} </div>
|
||||
<div>
|
||||
<label for="nntpchan_board_target">{{#i18n.Translations}}{{board_name_title}}{{/i18n.Translations}}:</label>
|
||||
<input id="nntpchan_board_target" />
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_board('frontend.add')">{{#i18n.Translations}}{{add_board_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_board('frontend.regen')">{{#i18n.Translations}}{{regenerate_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_board('frontend.ban')">{{#i18n.Translations}}{{ban_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_admin_board('frontend.unban')">{{#i18n.Translations}}{{unban_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin_board('frontend.nuke')">{{#i18n.Translations}}{{nuke_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<div>
|
||||
{{#i18n.Translations}}{{light_actions_label}}{{/i18n.Translations}}
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin('template.reload')">{{#i18n.Translations}}{{reload_templates_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<label>{{#i18n.Translations}}{{heavy_actions_label}}{{/i18n.Translations}}</label>
|
||||
<div>
|
||||
<button onclick="nntpchan_admin('frontend.regen')">{{#i18n.Translations}}{{regenerate_markup_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_admin('thumbnail.regen')">{{#i18n.Translations}}{{regenerate_thumbs_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_admin('feed.sync')">{{#i18n.Translations}}{{feed_sync_prompt}}{{/i18n.Translations}}</button>
|
||||
<button onclick="nntpchan_admin('store.expire')">{{#i18n.Translations}}{{expire_old_prompt}}{{/i18n.Translations}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nntpchan_mod_result"></div>
|
||||
<div id="nntpchan_feeds"></div>
|
||||
<script>
|
||||
// start nntp feed stats ticker
|
||||
var e = document.getElementById("nntpchan_feeds");
|
||||
if (e) {
|
||||
setInterval(function() {
|
||||
update_nntpchan_feed_ticker(e);
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
<noscript>
|
||||
<b>enable js to use the mod panel kthx</b>
|
||||
<b>{{#i18n.Translations}}{{nojs_info}}{{/i18n.Translations}}</b>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="navbar">
|
||||
<span class="navbar-name">
|
||||
<span class="board_title">{{name}}</span>
|
||||
on
|
||||
{{#i18n.Translations}}{{navbar_on}}{{/i18n.Translations}}
|
||||
<span class="frontend_title">{{frontend}}</span>
|
||||
</span>
|
||||
<span class="navbar-sep">
|
||||
@@ -31,16 +31,24 @@
|
||||
|
|
||||
</span>
|
||||
<span class="navbar-links">
|
||||
<span class="navbar-link"><a href="{{prefix}}">front page</a></span>
|
||||
<span class="navbar-link"><a href="{{prefix}}">{{#i18n.Translations}}{{front_page_title}}{{/i18n.Translations}}</a></span>
|
||||
</span>
|
||||
<span class="navbar-sep">
|
||||
|
|
||||
</span>
|
||||
<span class="navbar-links">
|
||||
<span class="navbar-link"><a href="{{prefix}}ukko.html">overboard</a></span>
|
||||
<span class="navbar-link"><a href="{{prefix}}ukko.html">{{#i18n.Translations}}{{overboard_title}}{{/i18n.Translations}}</a></span>
|
||||
</span>
|
||||
<span class="navbar-sep">
|
||||
|
|
||||
</span>
|
||||
<span class="navbar-links">
|
||||
<span class="navbar-link"><label onclick="enable_theme('{{prefix}}','bloodgod')">bloodgod</a></span>
|
||||
<span class="navbar-link"><label onclick="enable_theme('{{prefix}}','dayman')">dayman</a></span>
|
||||
<span class="navbar-link"><label onclick="enable_theme('{{prefix}}','site')">yotsuba</a></span>
|
||||
</span>
|
||||
<span class="navbar-sep">
|
||||
|
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<hr />
|
||||
|
||||
56
contrib/templates/default/newboard.mustache
Normal file
@@ -0,0 +1,56 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>{{#i18n.Translations}}{{new_board_title}}{{/i18n.Translations}}</title>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{prefix}}static/newboard.js">
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>{{#i18n.Translations}}{{first_post_label}}{{/i18n.Translations}}</p>
|
||||
<hr />
|
||||
<form action="{{prefix}}post/" enctype="multipart/form-data" name="post" method="post" id="postform" >
|
||||
<div id="postform-outer">
|
||||
<div id="postform-inner">
|
||||
<table class="postform">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{board_name_title}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="name" value="" id="boardname" />
|
||||
<button onclick="createBoard()">Create Board</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{comment}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<textarea id="postform_message" name="message" cols=40 rows=5></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{captcha}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<img id="captcha_img" src="{{prefix}}captcha/img" alt="captcha" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{solution}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="captcha" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
25
contrib/templates/default/overview.mustache
Normal file
@@ -0,0 +1,25 @@
|
||||
{{! overview.mustache
|
||||
paramters:
|
||||
|
||||
- overview (list of PostModels in order of last posted)
|
||||
|
||||
}}
|
||||
|
||||
<table id="overview_graph">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{#i18n.Translations}}{{newsgroup}}{{/i18n.Translations}}</th>
|
||||
<th>{{#i18n.Translations}}{{posted}}{{/i18n.Translations}}</th>
|
||||
<th>{{#i18n.Translations}}{{subject}}{{/i18n.Translations}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#overview}}
|
||||
<tr>
|
||||
<td><a href="{{Prefix}}{{Board}}-0.html">{{Board}}</td>
|
||||
<td>{{Date}}</td>
|
||||
<td><a href="{{PostURL}}">{{Truncate.Subject}}</a></td>
|
||||
</tr>
|
||||
{{/overview}}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1,43 +1,33 @@
|
||||
<div class="{{{CSSClass}}}" id="post_{{PostHash}}">
|
||||
<p class="intro">
|
||||
<label for="delete_{{PostHash}}">
|
||||
<span class="frontend">
|
||||
[[ {{Frontend}} ]]
|
||||
</span>
|
||||
<span class="subject">
|
||||
{{Subject}}
|
||||
</span>
|
||||
<span class="name">
|
||||
{{#Sage}}
|
||||
<a href="mailto:sage">
|
||||
{{Name}}
|
||||
</a>
|
||||
{{/Sage}}
|
||||
{{^Sage}}
|
||||
{{Name}}
|
||||
{{/Sage}}
|
||||
</span>
|
||||
<span class="postdate">
|
||||
{{Date}}
|
||||
</span>
|
||||
</label>
|
||||
<a href="{{PostURL}}" onclick="">No. {{ShortHash}}</a>
|
||||
{{#OP}}
|
||||
<a href="{{PostURL}}">[reply]</a>
|
||||
{{/OP}}
|
||||
<span class="tripcode">{{{Pubkey}}}</span>
|
||||
</p>
|
||||
<div class="files">
|
||||
{{#Attachments}}
|
||||
<div class="file">
|
||||
<p class="file_info">
|
||||
<span>File: {{Filename}}</span>
|
||||
</p>
|
||||
<a target="_blank" class="file-link" href="{{Source}}" title="{{Filename}}">
|
||||
<img class="file-thumbnail" src="{{Thumbnail}}" alt="{{Filename}}" />
|
||||
</a>
|
||||
</div>
|
||||
{{/Attachments}}
|
||||
<div id="{{post.PostHash}}" class="{{post.CSSClass}}">
|
||||
<legend class="postheader">
|
||||
<span class="origin">
|
||||
{{#post.IsI2P}}
|
||||
<img src="{{post.Prefix}}static/i2p.png" title="{{#i18n.Translations}}{{from_i2p}}{{/i18n.Translations}}" />
|
||||
{{/post.IsI2P}}
|
||||
{{#post.IsTor}}
|
||||
<img src="{{post.Prefix}}static/tor.png" title="{{#i18n.Translations}}{{from_tor}}{{/i18n.Translations}}" />
|
||||
{{/post.IsTor}}
|
||||
{{#post.IsClearnet}}
|
||||
<img src="{{post.Prefix}}static/clearnet.png" title="{{#i18n.Translations}}{{from_clearnet}}{{/i18n.Translations}}" />
|
||||
{{/post.IsClearnet}}
|
||||
</span>
|
||||
<span class="subject">{{post.Subject}}</span>
|
||||
<span class="name">{{post.Name}}</span>
|
||||
<time datetime="{{post.DateRFC}}">{{post.Date}}</time>
|
||||
<a href="#" class="postnol">No.</a><a class="postno" onclick="nntpchan_backlink('{{post.ShortHash}}');" title="{{post.MessageID}}">{{post.ShortHash}}</a>
|
||||
<a href="{{post.PostURL}}">[{{#i18n.Translations}}{{reply_label}}{{/i18n.Translations}}]</a>
|
||||
<span class="tripcode">{{{post.Pubkey}}}</span>
|
||||
</legend>
|
||||
<div class="attachments">
|
||||
{{#post.Attachments}}
|
||||
<figure>
|
||||
<figcaption>
|
||||
<a href="{{Source}}" title="{{Filename}}" target="_blank"><img src="{{Thumbnail}}" alt="{{Filename}}" class="thumbnail"/></a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{{/post.Attachments}}
|
||||
</div>
|
||||
<div class="post_body">{{{RenderBody}}}</div>
|
||||
</div>
|
||||
<div class="post_body">
|
||||
{{{post.RenderBody}}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<html>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{prefix}}static/nntpchan.js"></script>
|
||||
<meta http-equiv="refresh" content="1; {{redirect_url}}" />
|
||||
<body>
|
||||
<p>post failed: {{reason}}</p>
|
||||
<pre>{{#i18n.Translations}}{{post_failed_label}}{{/i18n.Translations}}: {{reason}}</pre>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
48
contrib/templates/default/post_retry.mustache
Normal file
@@ -0,0 +1,48 @@
|
||||
<html>
|
||||
<head>
|
||||
<title> try again </title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" name="post" method="post">
|
||||
{{#attachment}}
|
||||
<input type="hidden" name="attachment_data" value="{{attachment}}" />
|
||||
<input type="hidden" name="attachment_filename" value="{{attachment_filename}}" />
|
||||
<input type="hidden" name="attachment_mime" value="{{attachment_type}}" />
|
||||
{{/attachment}}
|
||||
<input type="hidden" name="reference" value="{{reference}}" />
|
||||
<input type="hidden" name="name" value="{{name}}" />
|
||||
<input type="hidden" name="subject" value="{{subject}}" />
|
||||
<input type="hidden" name="captcha_id" value="{{captcha_id}}" />
|
||||
<input type="hidden" name="message" value="{{message}}" />
|
||||
<div id="postform-outer">
|
||||
<div id="postform-inner">
|
||||
<div>{{fail_message}}</div>
|
||||
<table class="postform">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{captcha}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<img id="captcha_img" src="{{prefix}}captcha/{{captcha_id}}.png" alt="captcha" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{solution}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="captcha" />
|
||||
<input type="submit" value="Post" class="button" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,8 +5,12 @@
|
||||
- message_id ( the value of the Message-ID header in the post we made, the truncated sha1 of this is the >>posthash )
|
||||
}}
|
||||
<html>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{prefix}}static/nntpchan.js"></script>
|
||||
<meta http-equiv="refresh" content="2; {{redirect_url}}" />
|
||||
<body>
|
||||
<pre>posted as {{message_id}}</pre>
|
||||
<pre>{{#i18n.Translations}}{{posted_as_label}}{{/i18n.Translations}} {{message_id}}</pre>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
- post_url ( the url of the post form )
|
||||
- reference ( the post we are replying to, or empty string if it's an op )
|
||||
- button ( the text for the reply button )
|
||||
- files ( bool, do we allow attachments ? )
|
||||
- csrf ( csrf token )
|
||||
}}
|
||||
<form action="{{post_url}}" enctype="multipart/form-data" name="post" method="post">
|
||||
{{{csrf}}}
|
||||
<input type="hidden" name="reference" value="{{reference}}" />
|
||||
<div id="postform-outer">
|
||||
<div id="postform-inner">
|
||||
@@ -14,7 +17,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
Name
|
||||
{{#i18n.Translations}}{{name}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="name" value="" />
|
||||
@@ -22,7 +25,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Subject
|
||||
{{#i18n.Translations}}{{subject}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="subject" value="" />
|
||||
@@ -31,23 +34,33 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Comment
|
||||
{{#i18n.Translations}}{{comment}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<textarea type="text" name="message" cols=40 rows=5></textarea>
|
||||
<textarea id="postform_message" name="message" cols=40 rows=5></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
{{#files}}
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{file}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input class="postform_attachment" id="postform_attachments" type="file" name="attachment_uploaded" multiple />
|
||||
</td>
|
||||
</tr>
|
||||
{{/files}}
|
||||
<tr>
|
||||
<th>
|
||||
{{#i18n.Translations}}{{dubs}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="checkbox" name="dubs" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
File
|
||||
</th>
|
||||
<td>
|
||||
<input type="file" name="attachment" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Captcha
|
||||
{{#i18n.Translations}}{{captcha}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<img id="captcha_img" src="{{prefix}}captcha/img" alt="captcha" />
|
||||
@@ -55,10 +68,10 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Solution
|
||||
{{#i18n.Translations}}{{solution}}{{/i18n.Translations}}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="captcha" />
|
||||
<input type="text" name="captcha" autocomplete="off" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -66,4 +79,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<div class="thread_reply" id="post_{{PostHash}}">
|
||||
<p class="intro">
|
||||
<label for="delete_{{PostHash}}">
|
||||
<span class="subject">
|
||||
{{Subject}}
|
||||
</span>
|
||||
<span class="name">
|
||||
{{#Sage}}
|
||||
<a href="mailto:sage">
|
||||
{{Name}}
|
||||
</a>
|
||||
{{/Sage}}
|
||||
{{^Sage}}
|
||||
{{Name}}
|
||||
{{/Sage}}
|
||||
</span>
|
||||
<time
|
||||
</label>
|
||||
<a href="{{PostURL}}" onclick="">
|
||||
No. {{PostHash}}
|
||||
</a>
|
||||
</p>
|
||||
<div class="files">
|
||||
{{#Image}}
|
||||
<a class="file" href="{{Source}}">
|
||||
<img class="file-thumbnail" src="{{Thumbnail}}" />
|
||||
</a>
|
||||
{{/Image}}
|
||||
</div>
|
||||
<div class="thread_reply_body">
|
||||
{{{RenderBody}}}
|
||||
</div>
|
||||
</div>
|
||||
25
contrib/templates/default/posts_graph.mustache
Normal file
@@ -0,0 +1,25 @@
|
||||
{{!
|
||||
posts graph.mustache -- post frequence graph
|
||||
parameters:
|
||||
|
||||
* graph - a postsGraph instance (see srnd/model.go)
|
||||
}}
|
||||
|
||||
<table id="posts_graph">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{#i18n.Translations}}{{day}}{{/i18n.Translations}}</th>
|
||||
<th>{{#i18n.Translations}}{{posts}}{{/i18n.Translations}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#graph.Scale}}
|
||||
<tr>
|
||||
<td>{{Day}}</td>
|
||||
<td>{{Num}}</td>
|
||||
<td>{{OvercockGraph}}</td>
|
||||
</tr>
|
||||
{{/graph.Scale}}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -3,7 +3,6 @@
|
||||
template parameters:
|
||||
- board ( the Board Model of the board this thread was posted in )
|
||||
- thread ( the Thread Model of the current thread being rendered )
|
||||
- form ( the post form markup )
|
||||
|
||||
Thread Model attributes:
|
||||
- OP , the Post Model of the original poster
|
||||
@@ -14,15 +13,21 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{thread.Prefix}}static/site.css"></link>
|
||||
<meta name="viewport" content="initial-scale=1" />
|
||||
<link rel="stylesheet" href="{{thread.Prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{thread.Prefix}}static/user.css" />
|
||||
<script src="{{thread.Prefix}}static/nntpchan.js" type="text/javascript"></script>
|
||||
<title> {{thread.OP.Subject}} </title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<body onload="main()">
|
||||
<!-- begin navbar -->
|
||||
{{{thread.Navbar}}}
|
||||
<!-- end navbar -->
|
||||
|
||||
<center>
|
||||
<div id="nntpchan_banner">
|
||||
</div>
|
||||
</center>
|
||||
<div class="board_header">{{thread.Board}}</div>
|
||||
<!-- postform -->
|
||||
<div id="postform_container">
|
||||
{{{form}}}
|
||||
@@ -37,7 +42,17 @@
|
||||
<br/>
|
||||
{{/ thread.Replies}}
|
||||
</div>
|
||||
<br/>
|
||||
<hr/>
|
||||
<div class="navLinks">[<a href="{{thread.BoardURL}}" accesskey="a">{{#i18n.Translations}}{{return}}{{/i18n.Translations}}</a>] [<a href="{{thread.Prefix}}catalog-{{thread.Board}}.html" accesskey="r">{{#i18n.Translations}}{{catalog_label}}{{/i18n.Translations}}</a>] [<a href="#thread_{{thread.OP.PostHash}}">{{#i18n.Translations}}{{to_top_label}}{{/i18n.Translations}}</a>] [<a href="#navlinks" accesskey="r" onclick="location.reload();">{{#i18n.Translations}}{{update}}{{/i18n.Translations}}</a>]</div>
|
||||
<script type="text/javascript">
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, "{{thread.Prefix}}");
|
||||
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p class="legal">All posts on this site are the responsibility of the individual poster and not the administration, pursuant to 47 U.S.C. § 230.</p>
|
||||
<p class="legal">To make a DMCA request or report illegal content, please contact the administration</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -6,30 +6,44 @@
|
||||
}}
|
||||
<html>
|
||||
<head>
|
||||
<title> ukko / overboard </title>
|
||||
<title> {{#i18n.Translations}}{{overboard_title}}{{/i18n.Translations}} </title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css"></link>
|
||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
||||
<link id="current_theme" rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||
<script type="text/javascript" src="{{prefix}}static/nntpchan.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="ukko-topbar">
|
||||
<a href="{{prefix}}">Front Page</a>
|
||||
</div>
|
||||
<div id="ukko_threads" class="threads_container">
|
||||
<body onload="main()">
|
||||
<center>
|
||||
<div id="nntpchan_banner">
|
||||
</div>
|
||||
</center>
|
||||
<!-- begin navbar -->
|
||||
{{{navbar}}}
|
||||
<!-- end navbar -->
|
||||
<div class="board_header"> {{#i18n.Translations}}{{overboard_title}}{{/i18n.Translations}} </div>
|
||||
<div id="ukko_threads">
|
||||
{{#threads}}
|
||||
<div class="ukko_thread_header">
|
||||
<p> Posted on <a href="{{{BoardURL}}}"><span class="ukko_boardname">{{OP.Board}}</span></a></p>
|
||||
</div>
|
||||
<div class="thread" id="thread_{{OP.PostHash}}">
|
||||
<div clsss="thread_header">
|
||||
</div>
|
||||
{{{OP.RenderPost}}}
|
||||
<div class="ukko_thread_header">
|
||||
<p>{{#i18n.Translations}}{{posted_on_label}}{{/i18n.Translations}} <a href="{{{BoardURL}}}"><span class="ukko_boardname">{{OP.Board}}</span></a></p>
|
||||
</div>
|
||||
{{{OP.Truncate.RenderPost}}}
|
||||
{{#Truncate.Replies}}
|
||||
{{{Truncate.RenderPost}}}
|
||||
<br />
|
||||
{{/Truncate.Replies}}
|
||||
<hr />
|
||||
</div>
|
||||
<hr/>
|
||||
{{/threads}}
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" >
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, "{{prefix}}");
|
||||
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p class="legal">All posts on this site are the responsibility of the individual poster and not the administration, pursuant to 47 U.S.C. § 230.</p>
|
||||
<p class="legal">To make a DMCA request or report illegal content, please contact the administration</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
51
contrib/tools/api/moderate.js
Normal file
@@ -0,0 +1,51 @@
|
||||
var http = require('http');
|
||||
|
||||
var makeIpBans = function(cidrs, privkey, cb) {
|
||||
cb({
|
||||
message: cidrs.join("\noverchan-inet-ban "),
|
||||
name: "mod#"+privkey,
|
||||
frontend: "memegod.censor",
|
||||
newsgroup: "ctl"
|
||||
})
|
||||
}
|
||||
|
||||
var makeDeletePosts = function(msgids, privkey, cb) {
|
||||
cb({
|
||||
message: msgids.join("\ndelete "),
|
||||
name: "mod#"+privkey,
|
||||
frontend: "memegod.censor",
|
||||
newsgroup: "ctl",
|
||||
})
|
||||
}
|
||||
|
||||
var moderate = function(req) {
|
||||
|
||||
j = JSON.stringify(req);
|
||||
|
||||
var r = http.request({
|
||||
port: 8800,
|
||||
method: "POST",
|
||||
path: "/api/post",
|
||||
auth: "user:pass",
|
||||
headers: {
|
||||
"Content-Type": "text/json",
|
||||
"Content-Length": j.length
|
||||
}
|
||||
}, function (res) {
|
||||
res.on('data', function (chunk) {
|
||||
var r = chunk.toString();
|
||||
var rj = JSON.parse(r);
|
||||
console.log(rj.id);
|
||||
});
|
||||
});
|
||||
|
||||
r.write(j);
|
||||
r.end();
|
||||
}
|
||||
|
||||
var privateKey = "longhexgoestripcodegoeshere";
|
||||
|
||||
// ban 192.168.0.1/16 and sign with private key
|
||||
makeIpBans(["192.168.0.1/16"], privateKey, moderate);
|
||||
// delete <msg1@place.tld> and <msg2@otherplace.tld> and sign with private key
|
||||
makeDeletPosts(["<msg1@place.tld>", "<msg2@otherplace.tld>"], privateKey, moderate);
|
||||
44
contrib/tools/api/post.js
Normal file
@@ -0,0 +1,44 @@
|
||||
var http = require('http');
|
||||
|
||||
req = {
|
||||
message: "test api",
|
||||
frontend: "benis.tld",
|
||||
name: "benisname",
|
||||
subject: "ayyyyyy testing api",
|
||||
/*
|
||||
file: {
|
||||
name: "benis.gif",
|
||||
type: "image/gif",
|
||||
data: // base64'd string here
|
||||
},
|
||||
*/
|
||||
email: "sage",
|
||||
ip: "8.8.8.8",
|
||||
dubs: false,
|
||||
newsgroup: "overchan.test",
|
||||
|
||||
// only include if we are replying to someone
|
||||
reference: "<b7dee1453564515@benis.tld>"
|
||||
}
|
||||
|
||||
j = JSON.stringify(req);
|
||||
|
||||
var r = http.request({
|
||||
port: 8800,
|
||||
method: "POST",
|
||||
path: "/api/post",
|
||||
auth: "user:pass",
|
||||
headers: {
|
||||
"Content-Type": "text/json",
|
||||
"Content-Length": j.length
|
||||
}
|
||||
}, function (res) {
|
||||
res.on('data', function (chunk) {
|
||||
var r = chunk.toString();
|
||||
var rj = JSON.parse(r);
|
||||
console.log(rj.id);
|
||||
});
|
||||
});
|
||||
|
||||
r.write(j);
|
||||
r.end();
|
||||
204
contrib/tools/archive/nntparchive/archiver.py
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env python3.4
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup as BS
|
||||
|
||||
import datetime
|
||||
import io
|
||||
import nntplib
|
||||
import time
|
||||
import urllib.parse
|
||||
import base64
|
||||
import random
|
||||
|
||||
class Article:
|
||||
"""
|
||||
an nntp article
|
||||
"""
|
||||
|
||||
timeFormat = '%a, %d %b %Y %H:%M:%S +0000'
|
||||
|
||||
def __init__(self, j, board, site):
|
||||
"""
|
||||
construct article
|
||||
:param j: json object
|
||||
"""
|
||||
self.j = j
|
||||
self.board = board
|
||||
self.site = site
|
||||
self.messageID = self.genMessageID(j['no'])
|
||||
|
||||
def formatDate(self):
|
||||
return datetime.datetime.utcfromtimestamp(self.j['time']).strftime(self.timeFormat)
|
||||
|
||||
def message(self):
|
||||
m = ''
|
||||
# for each line
|
||||
for p in BS(self.j['com']).find_all('p'):
|
||||
# clean it
|
||||
m += p.text
|
||||
m += '\n'
|
||||
if len(m.rstrip('\n')) > 0:
|
||||
return m
|
||||
|
||||
def subject(self):
|
||||
if 'subject' in self.j:
|
||||
return self.j['subject']
|
||||
|
||||
def name(self):
|
||||
return self.j['name']
|
||||
|
||||
def group(self):
|
||||
return 'overchan.archive.{}.{}'.format(self.site, self.board)
|
||||
|
||||
def genMessageID(self, no):
|
||||
return '<{}.{}@{}>'.format(self.board, no, self.site)
|
||||
|
||||
def header(self):
|
||||
hdr = ("Subject: {}\n"+\
|
||||
"From: {} <archiver@srndv2.tools>\n"+\
|
||||
"Date: {}\n"+\
|
||||
"Newsgroups: {}\n"+\
|
||||
"Message-ID: {}\n"+\
|
||||
"Path: {}\n").format(self.subject(), self.name(), self.formatDate(), self.group(), self.messageID, self.site)
|
||||
if self.j['resto'] > 0:
|
||||
hdr += "References: {}\n".format(self.genMessageID(self.j['resto']))
|
||||
if 'filename' in self.j:
|
||||
hdr += 'Mime-Version: 1.0\n'
|
||||
hdr += 'Content-Type: multipart/mixed; boundary="{}"\n'.format(self.boundary)
|
||||
else:
|
||||
hdr += 'Content-Type: text/plain; encoding="UTF-8"\n'
|
||||
return hdr
|
||||
|
||||
def bodyPlain(self):
|
||||
msg = self.message()
|
||||
if msg:
|
||||
return "{}\n{}".format(self.header(), msg)
|
||||
|
||||
def getAttachmentPart(self, j):
|
||||
msg = ''
|
||||
mtype = 'image'
|
||||
if j['ext'] in ['.mp4', '.webm']:
|
||||
mtype = 'video'
|
||||
url = 'https://{}/{}/src/{}{}'.format(self.site, self.board, j['tim'], j['ext'])
|
||||
print ('obtain {}'.format(url))
|
||||
|
||||
r = requests.get(url)
|
||||
if r.status_code == 200:
|
||||
msg += '--{}\n'.format(self.boundary)
|
||||
msg += 'Content-Type: {}/{}\n'.format(mtype, j['ext'])
|
||||
msg += 'Content-Disposition: form-data; filename="{}{}"; name="import"\n'.format(j['filename'], j['ext'])
|
||||
msg += 'Content-Transfer-Encoding: base64\n'
|
||||
msg += '\n'
|
||||
msg += base64.b64encode(r.content).decode('ascii')
|
||||
msg += '\n'
|
||||
else:
|
||||
print ('failed to obtain attachment: {} != 200'.format(r.status_code))
|
||||
return msg
|
||||
|
||||
|
||||
def bodyMultipart(self):
|
||||
self.boundary = '========{}'.format(random.randint(0, 10000000))
|
||||
msg = self.header() + '\n'
|
||||
msg += '--{}\n'.format(self.boundary)
|
||||
msg += 'Content-Type: text/plain; encoding=UTF-8\n'
|
||||
msg += '\n'
|
||||
msg += self.message() + '\n'
|
||||
msg += self.getAttachmentPart(self.j)
|
||||
if 'extra_files' in self.j:
|
||||
for j in self.j['extra_files']:
|
||||
msg += self.getAttachmentPart(j)
|
||||
msg += '\n--{}--\n'.format(self.boundary)
|
||||
return msg
|
||||
|
||||
def body(self):
|
||||
if 'filename' in self.j:
|
||||
return self.bodyMultipart()
|
||||
else:
|
||||
return self.bodyPlain()
|
||||
|
||||
class Poster:
|
||||
|
||||
def __init__(self, host, port, user, passwd):
|
||||
self.host, self.port = host, port
|
||||
self.user, self.passwd = user, passwd
|
||||
|
||||
def post(self, articles):
|
||||
"""
|
||||
post 1 or more articles
|
||||
"""
|
||||
if isinstance(articles, Article):
|
||||
return self.post([articles])
|
||||
else:
|
||||
n = nntplib.NNTP(self.host, self.port, self.user, self.passwd)
|
||||
for article in articles:
|
||||
body = article.body()
|
||||
if body:
|
||||
print("posting {}".format(article.messageID))
|
||||
try:
|
||||
body = io.BytesIO(body.encode('utf-8'))
|
||||
n.ihave(article.messageID, body)
|
||||
except Exception as e:
|
||||
print('failed: {}'.format(e))
|
||||
n.quit()
|
||||
|
||||
|
||||
def url_parse(url):
|
||||
return urllib.parse.urlparse(url)
|
||||
|
||||
class Getter:
|
||||
|
||||
def __init__(self, url):
|
||||
self.url = url
|
||||
self.site = url_parse(url).hostname
|
||||
self.board = url_parse(url).path.split('/')[1]
|
||||
|
||||
def get(self, thread=False):
|
||||
"""
|
||||
yield a bunch of articles
|
||||
"""
|
||||
r = requests.get(self.url)
|
||||
if r.status_code == 200:
|
||||
try:
|
||||
j = r.json()
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if thread:
|
||||
if 'posts' in j:
|
||||
for post in j['posts']:
|
||||
yield Article(post, self.board, self.site)
|
||||
else:
|
||||
if 'threads' in j:
|
||||
for t in j['threads']:
|
||||
posts = t['posts']
|
||||
for post in posts:
|
||||
yield Article(post, self.board, self.site)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--server', type=str, required=True)
|
||||
ap.add_argument('--port', type=int, required=True)
|
||||
ap.add_argument('--board', type=str, required=True)
|
||||
ap.add_argument('--thread', type=str, required=False)
|
||||
ap.add_argument('--user', type=str, required=True)
|
||||
ap.add_argument('--passwd', type=str, requried=True)
|
||||
args = ap.parse_args()
|
||||
poster = Poster(args.server, args.port, args.user, args.passwd)
|
||||
|
||||
if args.thread:
|
||||
# only archive 1 thread
|
||||
getter = Getter('https://8ch.net/{}/res/{}.json'.format(args.board, thread))
|
||||
poster.post(getter.get(thread=True))
|
||||
else:
|
||||
# archive the entire board
|
||||
for n in range(10):
|
||||
getter = Getter('https://8ch.net/{}/{}.json'.format(args.board, n))
|
||||
poster.post(getter.get())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
10
contrib/tools/keys/keys.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# script to make sql file for inserting all "currently trusted" keys
|
||||
#
|
||||
|
||||
root=$(readlink -e $(dirname $0))
|
||||
touch $root/keys.sql
|
||||
for key in $(cat $root/keys.txt) ; do
|
||||
echo "insert into modprivs(pubkey, newsgroup, permission) values('$key', 'overchan', 'all');" >> keys.sql ;
|
||||
done
|
||||
10
contrib/tools/keys/keys.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('039a876792db66966241e63140e7df79df488033360064b67d890635814e925e', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('286650cac49fc540507a2b6593fa7aba7c5101e4314b6e5cfee1e64810a85bb7', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('c85aed0939fa1677bf9f354d8ac3dc9b1132cabea22b152247fa59cfc3d42d4f', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('fcd5fdffdb742a696a6d4df3a06d5c180aa523f2900b13fe893556832a1171f4', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('7227245429c46262baabfc3ce8e27b584b22262ad5c074bac4f05e0c7e2d9106', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('0c701740b6f6e799fb08354150265e19553535d2bd168f55067134d4a61449ac', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('ce39e0ea3c056e02e086063296c12fd36b8bf9530ab694bc645b48684004f946', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('d03da6ab445729f5f38f478fbefc5226bb1d58393a3b5a6852ec89c3ababc314', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('ce39e0ea3c056e02e086063296c12fd36b8bf9530ab694bc645b48684004f946', 'overchan', 'all');
|
||||
insert into modprivs(pubkey, newsgroup, permission) values('6440e2e383a802f2d487c71d2018b9dc53529e5d234e668c156aec97dae8fe6b', 'overchan', 'all');
|
||||
10
contrib/tools/keys/keys.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
039a876792db66966241e63140e7df79df488033360064b67d890635814e925e
|
||||
286650cac49fc540507a2b6593fa7aba7c5101e4314b6e5cfee1e64810a85bb7
|
||||
c85aed0939fa1677bf9f354d8ac3dc9b1132cabea22b152247fa59cfc3d42d4f
|
||||
fcd5fdffdb742a696a6d4df3a06d5c180aa523f2900b13fe893556832a1171f4
|
||||
7227245429c46262baabfc3ce8e27b584b22262ad5c074bac4f05e0c7e2d9106
|
||||
0c701740b6f6e799fb08354150265e19553535d2bd168f55067134d4a61449ac
|
||||
ce39e0ea3c056e02e086063296c12fd36b8bf9530ab694bc645b48684004f946
|
||||
d03da6ab445729f5f38f478fbefc5226bb1d58393a3b5a6852ec89c3ababc314
|
||||
ce39e0ea3c056e02e086063296c12fd36b8bf9530ab694bc645b48684004f946
|
||||
6440e2e383a802f2d487c71d2018b9dc53529e5d234e668c156aec97dae8fe6b
|
||||
209
contrib/tools/migrate/lynxchan/lynx2nntp.js
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env nodejs
|
||||
|
||||
var memegod = require("mongodb");
|
||||
var memegodClient = memegod.MongoClient;
|
||||
var assert = require("assert");
|
||||
var http = require("http");
|
||||
|
||||
|
||||
// memegod daemon url
|
||||
var url = "mongodb://127.0.0.1:27017/lynxchan";
|
||||
|
||||
// nntp frontend name for article import
|
||||
var frontendName = "memegod.import";
|
||||
// srndv2 http frontend server to do api requests against
|
||||
var srndApiServ = "localhost";
|
||||
var srndApiPort = 18000;
|
||||
// username password combo for using api
|
||||
var srndApiLogin = "user:pass";
|
||||
// some memegod thing
|
||||
var idPrefix="v1-";
|
||||
|
||||
|
||||
// create a newsgroup name given board name
|
||||
var makeGroupName = function(board) {
|
||||
return "overchan.test.endchan." + board.boardUri;
|
||||
}
|
||||
|
||||
// call function for each op on a board
|
||||
var foreachOpsOnBoard = function(db, board, callback, done) {
|
||||
var cur = db.collection("threads").find({boardUri: board});
|
||||
var ops = [];
|
||||
cur.each(function(err, doc) {
|
||||
if (doc) {
|
||||
ops.push(doc)
|
||||
} else {
|
||||
for (var idx = 0 ; ops.length > idx ; idx ++ ) {
|
||||
callback(ops[idx]);
|
||||
}
|
||||
if(done)
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// call a callback for each reply to op
|
||||
// pass in the memegod post
|
||||
var foreachReplyForOP = function(db, op, callback, done) {
|
||||
var doit = function(op, msgid) {// we don't has got it
|
||||
var cur = db.collection("posts").find({ threadId: op.threadId});
|
||||
var repls = [];
|
||||
cur.each(function(err, doc) {
|
||||
if (doc) {
|
||||
repls.push(doc)
|
||||
} else {
|
||||
for (var idx = 0 ; repls.length > idx ; idx ++ ) {
|
||||
callback(repls[idx]);
|
||||
}
|
||||
if(done)
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
checkPostExists(op, doit, doit);
|
||||
}
|
||||
|
||||
// find all boards in memegod
|
||||
// call callback for each board
|
||||
var foreachBoard = function(db, callback, done) {
|
||||
var cursor = db.collection('boards').find();
|
||||
var boards = [];
|
||||
cursor.each(function(err, doc) {
|
||||
if (doc) {
|
||||
boards.push(doc)
|
||||
} else {
|
||||
for (var idx = 0 ; boards.length > idx ; idx ++ ) {
|
||||
callback(boards[idx]);
|
||||
}
|
||||
if(done)
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// convert a memegod post from board into an overchan article
|
||||
// call a callback with the created post
|
||||
var createArticle = function(post, board, callback) {
|
||||
if (post == null) {
|
||||
callback(null);
|
||||
return
|
||||
}
|
||||
var article = {
|
||||
ip: post.ip.join("."),
|
||||
message: post.message || " ",
|
||||
subject: post.subject || "MongoDB is web scale",
|
||||
frontend: frontendName,
|
||||
newsgroup: makeGroupName(board),
|
||||
headers: {
|
||||
}
|
||||
};
|
||||
if (post.postId) {
|
||||
article.headers["X-Memegod-Post-Id"] = idPrefix+post.postId
|
||||
}
|
||||
if (post.threadId) {
|
||||
article.headers["X-Memegod-Thread-Id"] = idPrefix+post.threadId;
|
||||
}
|
||||
article.headers["X-Memegod-Id"] = idPrefix+post._id;
|
||||
article.headers["X-Migrated-From"] = "MemeGod";
|
||||
article.name = post.name || "Stephen Lynx";
|
||||
callback(article);
|
||||
}
|
||||
|
||||
// post an overchan article via the api
|
||||
// call callback passing in the message-id of the new post
|
||||
var postArticle = function(article, callback) {
|
||||
if (article == null) { callback(null); return; }
|
||||
checkViaHeader("X-Memegod-Id", article.headers["X-Memegod-Id"], function(msgid) {
|
||||
// we has got it already
|
||||
callback(msgid);
|
||||
}, function(msgid) {
|
||||
// we don't has got it
|
||||
var req = http.request({
|
||||
port: srndApiPort,
|
||||
method: "POST",
|
||||
path: "/api/post",
|
||||
auth: srndApiLogin,
|
||||
headers: {
|
||||
"Content-Type": "text/json",
|
||||
}
|
||||
}, function(res) {
|
||||
var data = "";
|
||||
res.on("data", function (chunk) {
|
||||
data += chunk;
|
||||
});
|
||||
res.on("end", function() {
|
||||
var j = JSON.parse(data)
|
||||
var msgid = j.id;
|
||||
callback(msgid);
|
||||
})
|
||||
});
|
||||
req.write(JSON.stringify(article));
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// check if an article exists given header name and header value
|
||||
var checkViaHeader = function(name, value, yesCb, noCb) {
|
||||
var req = http.request({
|
||||
port: srndApiPort,
|
||||
method: "GET",
|
||||
path: "/api/header?name="+name+"&value="+value,
|
||||
}, function (res) {
|
||||
var data = "";
|
||||
res.on("data", function(chnk) {
|
||||
data += chnk;
|
||||
});
|
||||
res.on("end", function() {
|
||||
var j = JSON.parse(data);
|
||||
if ( j.length > 0 ) {
|
||||
// it exists
|
||||
yesCb(j[0]);
|
||||
} else {
|
||||
// does not exist
|
||||
noCb();
|
||||
}
|
||||
});
|
||||
});
|
||||
req.end();
|
||||
}
|
||||
|
||||
// check if a post exists
|
||||
var checkPostExists = function(post, yescb, nocb) {
|
||||
checkViaHeader("X-Memegod-Id", idPrefix + post._id,
|
||||
function(msgid) { yescb(post, msgid); },
|
||||
function() { nocb(post); });
|
||||
}
|
||||
|
||||
var putBoard = function(db, board, done) {
|
||||
foreachOpsOnBoard(db, board.boardUri, function(originalPost) {
|
||||
var doit = function(op) {
|
||||
createArticle(op, board, function(opArticle) {
|
||||
postArticle(opArticle, function(opMsgId) {
|
||||
// for each reply for OP
|
||||
foreachReplyForOP(db, op, function(post) {
|
||||
checkPostExists(post , function(msgid) {
|
||||
// we have this post
|
||||
}, function(post, msgid) {
|
||||
// put create reply
|
||||
createArticle(post, board, function(article) {
|
||||
// set references header
|
||||
article.headers["References"] = opMsgId;
|
||||
postArticle(article, function(msgid) {});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
checkPostExists(originalPost, doit, doit);
|
||||
});
|
||||
}
|
||||
|
||||
memegodClient.connect(url, function(err, db) {
|
||||
console.log("connected to the meme god");
|
||||
foreachBoard(db, function(board) {
|
||||
console.log("updating "+board.boardUri);
|
||||
putBoard(db, board);
|
||||
});
|
||||
});
|
||||
117
contrib/translations/de-DE.ini
Normal file
@@ -0,0 +1,117 @@
|
||||
[formats]
|
||||
full_date_format=15:04:05 02.01.2006
|
||||
month_date_format=01.2006
|
||||
day_date_format=02.01
|
||||
|
||||
[strings]
|
||||
|
||||
#catalog
|
||||
catalog_title=Katalog für
|
||||
replies_short_label=A
|
||||
pictures_short_label=B
|
||||
|
||||
#board
|
||||
catalog_label=Katalog
|
||||
|
||||
#board list
|
||||
board_list_title=Boardliste
|
||||
board_label=Board
|
||||
pph_label=Posts pro Stunde
|
||||
ppd_label=Posts pro Tag
|
||||
total=Gesamt
|
||||
|
||||
#front page
|
||||
posts_today=Posts heute
|
||||
posts_hour=Posts diese Stunde
|
||||
|
||||
#history
|
||||
month=Monat
|
||||
posts=Posts
|
||||
post_history_title=Postverlauf
|
||||
|
||||
#keygen
|
||||
new_tripcode_title=Hier ist der neue Tripcode
|
||||
new_tripcode_label=Neuer Tripcode
|
||||
secret_key=Privater Schlüssel
|
||||
public_key=Öffentlicher Schlüssel
|
||||
tripcode=Tripcode
|
||||
|
||||
#login
|
||||
login=Anmeldung
|
||||
|
||||
#modpage
|
||||
modpage_title=nntpchan-Moderationsseite
|
||||
post_actions_label=Postfunktionen
|
||||
target_label=Ziel
|
||||
ban_url_prompt=Bannen (URL)
|
||||
delete_url_prompt=Löschen (URL)
|
||||
unban_ip_prompt=Bann aufheben (IP)
|
||||
key_actions_label=Schlüsselfunktionen
|
||||
pubkey_label=Öffentlicher Schlüssel
|
||||
add_key_prompt=Schlüssel hinzufügen
|
||||
remove_key_prompt=Schlüssen entfernen
|
||||
nntp_login_label=NNTP-Benutzer
|
||||
username=Benutzername
|
||||
password=Password
|
||||
add_user_prompt=Benutzer hinzufügen
|
||||
remove_user_prompt=Benutzer entfernen
|
||||
board_actions_label=Boardfunktionen
|
||||
board_name_title=Boardname
|
||||
add_board_prompt=Board hinzufügen
|
||||
regenerate_prompt=Regenerieren
|
||||
ban_prompt=Bannen
|
||||
unban_prompt=Bann aufheben
|
||||
nuke_prompt=Sprengen
|
||||
light_actions_label=Schnelle Funktionen
|
||||
reload_templates_prompt=Alle Templates erneut laden
|
||||
heavy_actions_label=Rechenintensive Funktionen (mit Vorsicht verwenden)
|
||||
regenerate_markup_prompt=Alle HTML-Seiten regenerieren
|
||||
regenerate_thumbs_prompt=Alle Vorschaubilder regenerieren
|
||||
nojs_info=Bitte aktivieren Sie JavaScript, um diese Seite zu nutzen.
|
||||
|
||||
#navbar
|
||||
navbar_on=@
|
||||
front_page_title=Startseite
|
||||
overboard_label=Überboard
|
||||
|
||||
#newboard
|
||||
new_board_title=Neues Board erstellen
|
||||
first_post_label=Machen Sie den ersten Post
|
||||
comment=Kommentar
|
||||
captcha=Captcha
|
||||
solution=Lösung
|
||||
|
||||
#overview
|
||||
newsgroup=Newsgroup
|
||||
posted=Gepostet
|
||||
subject=Betreff
|
||||
|
||||
#post
|
||||
from_i2p=Vom I2P-Netzwerk gepostet
|
||||
from_tor=Vom Tor-Netzwerk gepostet
|
||||
from_clearnet=Vom Clearnet gepostet
|
||||
reply_label=Antworten
|
||||
|
||||
#post failed
|
||||
post_failed_label=Post fehlgeschlagen
|
||||
|
||||
#post form
|
||||
name=Name
|
||||
file=Anhang
|
||||
dubs=Doppel?
|
||||
|
||||
#posts graph
|
||||
day=Tag
|
||||
|
||||
#post success
|
||||
posted_as_label=Gepostet als
|
||||
|
||||
#thread
|
||||
return=Zurück
|
||||
to_top_label=Nach oben
|
||||
update=Updaten
|
||||
|
||||
#ukko
|
||||
overboard_title=ukko / Überboard
|
||||
posted_on_label=Gepostet in
|
||||
|
||||
121
contrib/translations/en-US.ini
Normal file
@@ -0,0 +1,121 @@
|
||||
[formats]
|
||||
full_date_format=Mon Jan _2 15:04:05 2006
|
||||
month_date_format=2006-02
|
||||
day_date_format=01-02
|
||||
|
||||
[strings]
|
||||
|
||||
#catalog
|
||||
catalog_title=Catalog for
|
||||
replies_short_label=R
|
||||
pictures_short_label=P
|
||||
|
||||
#board
|
||||
catalog_label=Catalog
|
||||
|
||||
#board list
|
||||
board_list_title=board list
|
||||
board_label=Board
|
||||
pph_label=Posts per Hour
|
||||
ppd_label=Posts per Day
|
||||
total=Total
|
||||
|
||||
#front page
|
||||
posts_today=Posts Today
|
||||
posts_hour=Posts this Hour
|
||||
|
||||
#history
|
||||
month=Month
|
||||
posts=Posts
|
||||
post_history_title=Post History
|
||||
|
||||
#keygen
|
||||
new_tripcode_title=here is a new tripcode
|
||||
new_tripcode_label=New Tripcode
|
||||
secret_key=secret
|
||||
public_key=public
|
||||
tripcode=tripcode
|
||||
|
||||
#login
|
||||
login=login
|
||||
|
||||
#modpage
|
||||
modpage_title=nntpchan mod page
|
||||
post_actions_label=post actions
|
||||
target_label=target
|
||||
ban_url_prompt=ban (url)
|
||||
delete_url_prompt=delete (url)
|
||||
unban_ip_prompt=unban (ip)
|
||||
key_actions_label=key actions
|
||||
pubkey_label=pubkey
|
||||
add_key_prompt=add key
|
||||
remove_key_prompt=remove key
|
||||
nntp_login_label=nntp login
|
||||
username=username
|
||||
password=password
|
||||
add_user_prompt=add user
|
||||
remove_user_prompt=remove user
|
||||
board_actions_label=board actions
|
||||
board_name_title=board name
|
||||
add_board_prompt=add board
|
||||
regenerate_prompt=regenerate
|
||||
ban_prompt=ban
|
||||
unban_prompt=unban
|
||||
nuke_prompt=nuke
|
||||
light_actions_label=lightweight actions
|
||||
reload_templates_prompt=reload all templates
|
||||
heavy_actions_label=very load heavy actions, use with care
|
||||
regenerate_markup_prompt=regenerate all markup
|
||||
regenerate_thumbs_prompt=regenerate all thumbnails
|
||||
feed_sync_prompt=manually synchronize all articles
|
||||
expire_old_prompt=manually expire orphaned articles
|
||||
nojs_info=enable js to use the mod panel kthx
|
||||
|
||||
#navbar
|
||||
navbar_on=on
|
||||
front_page_title=front page
|
||||
overboard_title=overboard
|
||||
|
||||
#newboard
|
||||
new_board_title=create new board
|
||||
first_post_label=make your first post
|
||||
comment=Comment
|
||||
captcha=Captcha
|
||||
solution=Solution
|
||||
|
||||
#overview
|
||||
newsgroup=Newsgroup
|
||||
posted=Posted
|
||||
subject=Subject
|
||||
|
||||
#post
|
||||
from_i2p=posted from i2p
|
||||
from_tor=posted from tor
|
||||
from_clearnet=posted from clearnet
|
||||
reply_label=Reply
|
||||
|
||||
#post failed
|
||||
post_failed_label=post failed
|
||||
|
||||
#post form
|
||||
name=Name
|
||||
file=File
|
||||
dubs=Get Dubs
|
||||
|
||||
#posts graph
|
||||
day=Day
|
||||
|
||||
#post success
|
||||
posted_as_label=posted as
|
||||
|
||||
#thread
|
||||
return=Return
|
||||
to_top_label=Top
|
||||
update=Update
|
||||
|
||||
#ukko
|
||||
overboard_title=ukko / overboard
|
||||
posted_on_label=Posted on
|
||||
|
||||
#404 page
|
||||
resource_not_found=The page you are looking for isn't here
|
||||
117
contrib/translations/es-ES.ini
Normal file
@@ -0,0 +1,117 @@
|
||||
[formats]
|
||||
full_date_format=Lunes 2_Enero 15:04:05 2006
|
||||
month_date_format=02-2006
|
||||
day_date_format=01-02
|
||||
|
||||
[strings]
|
||||
|
||||
#catalog
|
||||
catalog_title=Catálogo para
|
||||
replies_short_label=R
|
||||
pictures_short_label=P
|
||||
|
||||
#board
|
||||
catalog_label=Catálogo
|
||||
|
||||
#board list
|
||||
board_list_title=Lista de canales
|
||||
board_label=Canales
|
||||
pph_label=Envíos a la hora
|
||||
ppd_label=Envíos al Día
|
||||
total=Total
|
||||
|
||||
#front page
|
||||
posts_today=Envíos de hoy
|
||||
posts_hour=Envíos de esta última hora
|
||||
|
||||
#history
|
||||
month=Mes
|
||||
posts=Envíos
|
||||
post_history_title=Historial de envíos
|
||||
|
||||
#keygen
|
||||
new_tripcode_title=Esto es un nuevo tripcode
|
||||
new_tripcode_label=Nuevo Tripcode
|
||||
secret_key=secreto
|
||||
public_key=público
|
||||
tripcode=tripcode
|
||||
|
||||
#login
|
||||
login=inicio de sesión
|
||||
|
||||
#modpage
|
||||
modpage_title=página configuración nntpchan
|
||||
post_actions_label=acciones de envíos
|
||||
target_label=objetivo
|
||||
ban_url_prompt=prohibir (url)
|
||||
delete_url_prompt=borrar (url)
|
||||
unban_ip_prompt=permitir (ip)
|
||||
key_actions_label=opciones de claves
|
||||
pubkey_label=pubkey
|
||||
add_key_prompt=añadir clave
|
||||
remove_key_prompt=eliminar clave
|
||||
nntp_login_label=inicio de sesión nntp
|
||||
username=nombre de usuario
|
||||
password=contraseña
|
||||
add_user_prompt=añadir usuario
|
||||
remove_user_prompt=eliminar usuario
|
||||
board_actions_label=acciones sobre los canales
|
||||
board_name_title=nombre del canal
|
||||
add_board_prompt=añadir canal
|
||||
regenerate_prompt=regenerar
|
||||
ban_prompt=prohibir
|
||||
unban_prompt=permitir
|
||||
nuke_prompt=destruir
|
||||
light_actions_label=acciones sencillas
|
||||
reload_templates_prompt=recargar todas las plantillas
|
||||
heavy_actions_label=acciones que consumen muchos recursos, usar con cuidado
|
||||
regenerate_markup_prompt=regenerar todos los formatos
|
||||
regenerate_thumbs_prompt=regenerar todas las miniaturas
|
||||
nojs_info=habilitar JS para utilizar el panel de mods kthx
|
||||
|
||||
#navbar
|
||||
navbar_on=on
|
||||
front_page_title=página principal
|
||||
overboard_title=overboard
|
||||
|
||||
#newboard
|
||||
new_board_title=crear un nuevo canal
|
||||
first_post_label=crear tu primer envío
|
||||
comment=Comentario
|
||||
captcha=Captcha
|
||||
solution=Solución
|
||||
|
||||
#overview
|
||||
newsgroup=Grupo de noticias
|
||||
posted=Enviado
|
||||
subject=Asunto
|
||||
|
||||
#post
|
||||
from_i2p=enviado desde i2p
|
||||
from_tor=enviado desde tor
|
||||
from_clearnet=enviado desde clearnet
|
||||
reply_label=Responder
|
||||
|
||||
#post failed
|
||||
post_failed_label=el envío a fallado
|
||||
|
||||
#post form
|
||||
name=Nombre
|
||||
file=Archivo
|
||||
dubs=Obtener 'Dubs' (dobles)
|
||||
|
||||
#posts graph
|
||||
day=Día
|
||||
|
||||
#post success
|
||||
posted_as_label=enviado como
|
||||
|
||||
#thread
|
||||
return=Volver
|
||||
to_top_label=Arriba
|
||||
update=Actualizar
|
||||
|
||||
#ukko
|
||||
overboard_title=ukko / overboard
|
||||
posted_on_label=Enviado en
|
||||
|
||||
116
contrib/translations/pt-BR.ini
Normal file
@@ -0,0 +1,116 @@
|
||||
[formats]
|
||||
full_date_format=Segunda, _2 de Janeiro 15:04:05 2006
|
||||
month_date_format=20-2006
|
||||
day_date_format=01-02
|
||||
|
||||
[strings]
|
||||
|
||||
#catalog
|
||||
catalog_title=Catálogo para
|
||||
replies_short_label=R
|
||||
pictures_short_label=I
|
||||
|
||||
#board
|
||||
catalog_label=Menu
|
||||
|
||||
#board list
|
||||
board_list_title=lista de canais
|
||||
board_label=Canais
|
||||
pph_label=Envios por hora
|
||||
ppd_label=Envios por dia
|
||||
total=Total
|
||||
|
||||
#front page
|
||||
posts_today=Envios hoje
|
||||
posts_hour=Envios na ultima hora
|
||||
|
||||
#history
|
||||
month=Mês
|
||||
posts=Envios
|
||||
post_history_title=Histórico
|
||||
|
||||
#keygen
|
||||
new_tripcode_title=Isto é um novo tripcode
|
||||
new_tripcode_label=Novo tripcode
|
||||
secret_key=segredo
|
||||
public_key=público
|
||||
tripcode=tripcode
|
||||
|
||||
#login
|
||||
login=login
|
||||
|
||||
#modpage
|
||||
modpage_title=Página de configuração do nntpchan
|
||||
post_actions_label=ações dos envios
|
||||
target_label=objetivo
|
||||
ban_url_prompt=banir (url)
|
||||
delete_url_prompt=deletar (url)
|
||||
unban_ip_prompt=permitir (ip)
|
||||
key_actions_label=opções de teclas
|
||||
pubkey_label=pubkey
|
||||
add_key_prompt=adicionar chave
|
||||
remove_key_prompt=remover chave
|
||||
nntp_login_label=iniciar sessão nntp
|
||||
username=nome de usuário
|
||||
password=senha
|
||||
add_user_prompt=adicionar usuário
|
||||
remove_user_prompt=remover usuário
|
||||
board_actions_label=ações de canais
|
||||
board_name_title=nome do canal
|
||||
add_board_prompt=adicionar canal
|
||||
regenerate_prompt=gerar novamente
|
||||
ban_prompt=banir
|
||||
unban_prompt=permitir
|
||||
nuke_prompt=destruir
|
||||
light_actions_label=ações leves
|
||||
reload_templates_prompt=recarregar todos os padrões
|
||||
heavy_actions_label=ações que consumem muitos recursos, usar com cuidado
|
||||
regenerate_markup_prompt=recarregar todos os formatos
|
||||
regenerate_thumbs_prompt=recarregar todas as miniaturas
|
||||
nojs_info=habilitar JS para usar o painel de mods kthx
|
||||
|
||||
#navbar
|
||||
navbar_on=on
|
||||
front_page_title=página inicial
|
||||
overboard_title=overboard
|
||||
|
||||
#newboard
|
||||
new_board_title=criar um novo canal
|
||||
first_post_label=fazer seu primeiro envio
|
||||
comment=Comentário
|
||||
captcha=Captcha
|
||||
solution=Solução
|
||||
|
||||
#overview
|
||||
newsgroup=Grupo de notícias
|
||||
posted=Enviado
|
||||
subject=Assunto
|
||||
|
||||
#post
|
||||
from_i2p=enviado da i2p
|
||||
from_tor=enviado da tor
|
||||
from_clearnet=enviado da clearnet
|
||||
reply_label=Responder
|
||||
|
||||
#post failed
|
||||
post_failed_label=o envio falhou
|
||||
|
||||
#post form
|
||||
name=Nome
|
||||
file=Arquivo
|
||||
dubs=Obter "Dubs" (pares)
|
||||
|
||||
#posts graph
|
||||
day=Dia
|
||||
|
||||
#post success
|
||||
posted_as_label=enviado como
|
||||
|
||||
#thread
|
||||
return=Voltar
|
||||
to_top_label=Acima
|
||||
update=Atualizar
|
||||
|
||||
#ukko
|
||||
overboard_title=ukko / overboard
|
||||
posted_on_label=Enviado em
|
||||
116
contrib/translations/ru-RU.ini
Normal file
@@ -0,0 +1,116 @@
|
||||
[formats]
|
||||
full_date_format=_2 Янв 2006 г. Пн 15:04:05
|
||||
month_date_format=01.2006
|
||||
day_date_format=02.01
|
||||
|
||||
[strings]
|
||||
|
||||
#catalog
|
||||
catalog_title=Каталог
|
||||
replies_short_label=О
|
||||
pictures_short_label=И
|
||||
|
||||
#board
|
||||
catalog_label=Каталог
|
||||
|
||||
#board list
|
||||
board_list_title=Список досок
|
||||
board_label=Доска
|
||||
pph_label=Постов в час
|
||||
ppd_label=Постов в день
|
||||
total=Всего
|
||||
|
||||
#front page
|
||||
posts_today=Постов за сегодня
|
||||
posts_hour=Постов за этот час
|
||||
|
||||
#history
|
||||
month=Месяц
|
||||
posts=Посты
|
||||
post_history_title=История поста
|
||||
|
||||
#keygen
|
||||
new_tripcode_title=вот новый трипкод
|
||||
new_tripcode_label=Новый трипкод
|
||||
secret_key=закрытый
|
||||
public_key=открытый
|
||||
tripcode=трипкод
|
||||
|
||||
#login
|
||||
login=войти
|
||||
|
||||
#modpage
|
||||
modpage_title=страница модерации nntpchan
|
||||
post_actions_label=опции поста
|
||||
target_label=цель
|
||||
ban_url_prompt=забанить (url)
|
||||
delete_url_prompt=удалить (url)
|
||||
unban_ip_prompt=разбанить (ip)
|
||||
key_actions_label=опции ключа
|
||||
pubkey_label=открытый ключ
|
||||
add_key_prompt=добавить ключ
|
||||
remove_key_prompt=удалить ключ
|
||||
nntp_login_label=nntp авторизация
|
||||
username=имя пользователя
|
||||
password=пароль
|
||||
add_user_prompt=добавить пользователя
|
||||
remove_user_prompt=удалить пользователя
|
||||
board_actions_label=опции доски
|
||||
board_name_title=название доски
|
||||
add_board_prompt=добавить доску
|
||||
regenerate_prompt=восстановить
|
||||
ban_prompt=забанить
|
||||
unban_prompt=разбанить
|
||||
nuke_prompt=уничтожить
|
||||
light_actions_label=малопотребляющие опции
|
||||
reload_templates_prompt=перезагрузить все шаблоны
|
||||
heavy_actions_label=многопотребляющие опции (использовать с осторожностью)
|
||||
regenerate_markup_prompt=восстановить всю разметку
|
||||
regenerate_thumbs_prompt=восстановить все миниатюры
|
||||
nojs_info=включи JS чтобы пользоваться панелью модерации ок спс
|
||||
|
||||
#navbar
|
||||
navbar_on=вкл
|
||||
front_page_title=главная страница
|
||||
overboard_title=сверхдоска
|
||||
|
||||
#newboard
|
||||
new_board_title=создать новую доску
|
||||
first_post_label=сделай свой первый пост
|
||||
comment=Комментарий
|
||||
captcha=Капча
|
||||
solution=Ответ
|
||||
|
||||
#overview
|
||||
newsgroup=Группа новостей
|
||||
posted=Отправлено
|
||||
subject=Тема
|
||||
|
||||
#post
|
||||
from_i2p=отправлено через i2p
|
||||
from_tor=отправлено через tor
|
||||
from_clearnet=отправлено через чистонет
|
||||
reply_label=Ответить
|
||||
|
||||
#post failed
|
||||
post_failed_label=отправка не удалась
|
||||
|
||||
#post form
|
||||
name=Имя
|
||||
file=Файл
|
||||
dubs=Получить Дабл
|
||||
|
||||
#posts graph
|
||||
day=День
|
||||
|
||||
#post success
|
||||
posted_as_label=отправлено как
|
||||
|
||||
#thread
|
||||
return=Вернуться
|
||||
to_top_label=К началу
|
||||
update=Обновить
|
||||
|
||||
#ukko
|
||||
overboard_title=ukko / сверхдоска
|
||||
posted_on_label=Опубликованно в
|
||||
11
doc/api.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# nntpchan jsonrpc api
|
||||
|
||||
To enable set the following in `srnd.ini` section `frontend`
|
||||
|
||||
[frontend]
|
||||
...
|
||||
json-api = 1
|
||||
json-api-username = something-really-long
|
||||
json-api-password = somethine-different-but-also-very-long
|
||||
|
||||
see the example tool at `contrib/tools/api/post.js`
|
||||
55
doc/build.md
@@ -4,53 +4,34 @@
|
||||
## requirements ##
|
||||
|
||||
* linux or freebsd
|
||||
* go 1.4 or higher
|
||||
* libsodium 1.0 or higher
|
||||
* imagemagick
|
||||
* RabbitMQ
|
||||
* ffmpegthumbnailer
|
||||
* sox
|
||||
|
||||
## supported go versions ##
|
||||
|
||||
* `go 1.6` or higher with redis driver
|
||||
|
||||
* `go 1.3` or higher without redis driver
|
||||
|
||||
## debian ##
|
||||
|
||||
Debian Jessie has go 1.3, we need 1.4 or higher to build the nntpchan daemon so let's do that first, assumes 64bit linux:
|
||||
|
||||
#
|
||||
# --->> DO NOT RUN AS ROOT <<---
|
||||
# (you probably will break stuff really bad if you do)
|
||||
#
|
||||
Get the dependancies
|
||||
|
||||
# make directory for go's packages
|
||||
mkdir -p $HOME/go
|
||||
|
||||
# set up a directory for our go distribution
|
||||
mkdir -p $HOME/local
|
||||
cd $HOME/local
|
||||
|
||||
# obtain and unpack go binary distribution
|
||||
wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz -O go-stable.tar.gz
|
||||
tar -xzvf go-stable.tar.gz
|
||||
|
||||
# set up environmental variables for go
|
||||
export GOROOT=$HOME/local/go
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$GOROOT/bin:$GOPATH/bin:$PATH
|
||||
|
||||
# put environmental variables in bash_alises for later
|
||||
echo 'export GOROOT=$HOME/local/go' >> $HOME/.bash_aliases
|
||||
echo 'export GOPATH=$HOME/go' >> $HOME/.bash_aliases
|
||||
echo 'export PATH=$GOROOT/bin:$GOPATH/bin:$PATH' >> $HOME/.bash_aliases
|
||||
sudo apt-get update
|
||||
sudo apt-get --no-install-recommends install imagemagick libsodium-dev ffmpegthumbnailer sox build-essential git golang ca-certificates
|
||||
|
||||
|
||||
We'll also need to install some dependancies that come with debian:
|
||||
Check out the repo and build it
|
||||
|
||||
# as root
|
||||
git clone https://github.com/majestrate/nntpchan
|
||||
cd nntpchan
|
||||
./build.sh
|
||||
|
||||
apt update
|
||||
apt install imagemagick libsodium-dev
|
||||
If you want to build without supporting redis then build with the `--no-redis` flag
|
||||
|
||||
Now build the daemon:
|
||||
|
||||
go get github.com/majestrate/srndv2
|
||||
go install github.com/majestrate/srndv2
|
||||
|
||||
It will create an executable at $GOPATH/bin/srndv2 which is already in our $PATH so it can be run by typing ``srndv2``
|
||||
./build.sh --no-redis
|
||||
|
||||
Now configure the database. [next](database.md)
|
||||
|
||||
20
doc/cli.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# command line interface
|
||||
|
||||
# rebuild all thumbnails
|
||||
srndv2 tool rethumb
|
||||
|
||||
# generate a new tripcode keypair
|
||||
# print out to stdout
|
||||
srndv2 tool keygen
|
||||
|
||||
# add an nntp login
|
||||
srndv2 tool nntp add-login username password
|
||||
|
||||
# remove an nntp login
|
||||
srndv2 tool nntp del-login username
|
||||
|
||||
# add public key to moderation trust
|
||||
srndv2 tool mod add publickeygoeshere
|
||||
|
||||
# remove public key from moderation trust
|
||||
srndv2 tool mod del publickeygoeshere
|
||||
9
doc/configuration.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Configuration #
|
||||
|
||||
In nntpchan's stack there are currently 2 configuration files.
|
||||
|
||||
All config files are auto generated with sane defaults if the files are not present.
|
||||
|
||||
[feeds.ini](feeds.md) is for all your nntp outfeeds
|
||||
|
||||
[srnd.ini](srnd.md) is for the core daemon
|
||||
@@ -1,23 +1,5 @@
|
||||
You have 2 choices for database backend:
|
||||
|
||||
Postgres on Debian:
|
||||
|
||||
|
||||
# install
|
||||
apt-get install postgresql postgresql-client
|
||||
|
||||
|
||||
Setting up postgres (as root)
|
||||
|
||||
# become postgres user
|
||||
su postgres
|
||||
# spawn postgres admin shell
|
||||
psql
|
||||
|
||||
You'll get a prompt, enter the following:
|
||||
|
||||
CREATE ROLE srnduser WITH LOGIN PASSWORD 'srndpassword';
|
||||
CREATE DATABASE srnd WITH ENCODING 'UTF8' OWNER srnduser;
|
||||
\q
|
||||
|
||||
Change the username and password as desired.
|
||||
* [postgres](postgres.md)
|
||||
|
||||
* [redis](redis.md)
|
||||
|
||||
180
doc/feeds.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# feeds.ini #
|
||||
|
||||
## Peering ##
|
||||
|
||||
In order to actually be distributed, you need another person to sync posts with, otherwise what's the point right?
|
||||
|
||||
### Peering over the regular internet with tls ###
|
||||
|
||||
Requirements:
|
||||
|
||||
* Each Side's server must have a domain name
|
||||
* Each Side must have each other's certificates (.crt files) in the `certs` folder
|
||||
* Each Side's `srnd.ini` crypto section must have entry `tls-hostname = domain.tld` where domain.tld is the domain name of the server it is on
|
||||
* Each Side's `srnd.ini` nntp section must have entry `require_tls = 1`
|
||||
|
||||
|
||||
If Alice owns `nntp.alice.net` and Bob owns `nntp.bob.com` and are both using port 1199 the configs for each side are as follows:
|
||||
|
||||
# alice's srnd.ini crypto section
|
||||
...
|
||||
[crypto]
|
||||
tls-hostname = nntp.alice.net
|
||||
tls-trust-dir = certs
|
||||
tls-keyname = overchan-alice
|
||||
|
||||
|
||||
# alice's feeds.ini
|
||||
[feed-bob]
|
||||
host = nntp.bob.com
|
||||
port = 1199
|
||||
|
||||
[bob]
|
||||
overchan.* = 1
|
||||
ctl = 1
|
||||
|
||||
|
||||
|
||||
# bob's srnd.ini crypto section
|
||||
...
|
||||
[crypto]
|
||||
tls-hostname = nntp.bob.com
|
||||
tls-trust-dir = certs
|
||||
tls-keyname = overchan-bob
|
||||
|
||||
|
||||
|
||||
# bob's feeds.ini
|
||||
[feed-alice]
|
||||
host = nntp.alice.net
|
||||
port = 1199
|
||||
|
||||
[alice]
|
||||
overchan.* = 1
|
||||
ctl = 1
|
||||
|
||||
each side's `certs` directory contains 2 files:
|
||||
|
||||
* overchan-alice-nntp.alice.net.crt (alice's certificate)
|
||||
* overchan-bob-nntp.bob.com.crt (bob's certificate)
|
||||
|
||||
Alice keeps `overchan-alice-nntp.alice.net.key` secret and never shares it
|
||||
|
||||
Bob keeps `overchan-bob-nntp.bob.com.key` secret and never shares it
|
||||
|
||||
|
||||
### Peering Authentication with passwords ###
|
||||
|
||||
adding / removing credentials via the command line:
|
||||
|
||||
# add an nntp login via command line
|
||||
srndv2 tool nntp add-login user-name-here pass-word-here
|
||||
|
||||
# remove an nntp login via command line
|
||||
srndv2 tool nntp del-login user-name-here
|
||||
|
||||
exmaple feeds.ini:
|
||||
|
||||
# section pair in feeds.ini
|
||||
# connects to nntp.something.tld:1199 and authenticates with a username and password
|
||||
# sync = 1 makes you download all applicable posts from the remote server on startup
|
||||
|
||||
[feed-authenticated]
|
||||
host = nntp.something.tld
|
||||
port = 1199
|
||||
username = user-user-here
|
||||
password = pass-word-here
|
||||
sync = 1
|
||||
|
||||
[authenticated]
|
||||
overchan.* = 1
|
||||
ctl = 1
|
||||
|
||||
|
||||
### Peering over tor ###
|
||||
|
||||
Install tor
|
||||
|
||||
apt-get install tor
|
||||
|
||||
Make a tor hidden service point from outside port 119 to port 1199
|
||||
Add to /etc/tor/torrc:
|
||||
|
||||
HiddenServiceDir /var/lib/tor/nntp_feed
|
||||
HiddenServicePort 119 127.0.0.1:1199
|
||||
|
||||
restart/reload tor then
|
||||
|
||||
cat /var/lib/tor/nntp_feed/hostname
|
||||
|
||||
This is your in feed address
|
||||
|
||||
If you use an onion with tls, `srnd.ini` crypto section should have the entry `tls-hostname = youroniongoeshere.onion`. If you don't use tls NEVER disclose the onion address to anyone not trusted.
|
||||
|
||||
Then to peer with someone over tor add this to you feeds.ini
|
||||
|
||||
[feed-ourpeer.onion]
|
||||
host=PeersOnionAddress.onion
|
||||
port=119
|
||||
proxy-type=socks4a
|
||||
proxy-host=127.0.0.1
|
||||
proxy-port=9050
|
||||
|
||||
[ourpeer.onion]
|
||||
overchan=1
|
||||
ctl=1
|
||||
|
||||
|
||||
## Options ##
|
||||
|
||||
#### You need one connection and one settings block for each connection ####
|
||||
|
||||
Here is an example entry in feeds.ini
|
||||
|
||||
[feed-them.onion]
|
||||
host=aabbccddeeff2233.onion
|
||||
port=119
|
||||
proxy-type=socks4a
|
||||
proxy-host=127.0.0.1
|
||||
proxy-port=9050
|
||||
username=somerandomusername
|
||||
password=somerandompassword
|
||||
|
||||
[them.onion]
|
||||
overchan=1
|
||||
ano.paste=0
|
||||
ctl=1
|
||||
|
||||
But what does it mean?
|
||||
|
||||
[feed-them.onion]
|
||||
|
||||
Connection settings for a peer
|
||||
|
||||
host=aabbccddeeff2233.onion
|
||||
port=119
|
||||
proxy-type=socks4a
|
||||
proxy-host=127.0.0.1
|
||||
proxy-port=9050
|
||||
|
||||
Proxy settings, straight forward. Supported proxy types are `socks4a` and `none`
|
||||
|
||||
[them.onion]
|
||||
|
||||
nntp synchronization settings
|
||||
|
||||
overchan=1
|
||||
|
||||
Sync all boards, use
|
||||
|
||||
overchan.bad=0
|
||||
|
||||
to prevent certain boards from syncing with certain peers. It can be used to keep bad boards out or keep exclusive boards in
|
||||
|
||||
ano.paste=0
|
||||
|
||||
This WILL be the nntpchan pastebin, but it's not implimented yet
|
||||
|
||||
ctl=1
|
||||
|
||||
Allows you to recieve moderation notifications from other boards, it's also used for decentralized moderation
|
||||
@@ -1,52 +0,0 @@
|
||||
## peering with other nodes ##
|
||||
|
||||
In order to actually be distributed, you need another person to sync posts with, otherwise what's the point right?
|
||||
|
||||
Right now peering information is private, there is no link level authenticatio (yet) so everything is done via either a vpn tunnel or a tor hidden service.
|
||||
|
||||
### Peering via cjdns vpn tunnel ###
|
||||
|
||||
Set up cjdns, read more [here](https://github.com/cjdelisle/cjdns/blob/master/doc/configure.md#connection-interfaces)
|
||||
|
||||
git clone https://github.com/cjdelisle/cjdns
|
||||
cd cjdns && ./do
|
||||
./cjdroute --genconf >> cjdroute.conf
|
||||
./cjdroute < cjdroute.conf
|
||||
|
||||
Get your ipv6 address for cjdns
|
||||
|
||||
ip addr show tun0
|
||||
|
||||
Edit srnd.ini to bind nntp on that ipv6 address, make sure to use the square brances `[` and `]`
|
||||
|
||||
[nntp]
|
||||
...
|
||||
bind=[xxxx:xxxx:xxxx:xxx:xx....]:1199
|
||||
|
||||
|
||||
say you have 2 friends at fc33:3:3::aadd and fc03:9f:123::a3df. right now feeds.ini can't take raw ipv6 addresses so add them to `/etc/hosts`
|
||||
|
||||
# add these lines to /etc/hosts
|
||||
fc33:3:3::aadd bob
|
||||
fc03:9f:123::a3df charlie
|
||||
|
||||
then add to feeds.ini the following:
|
||||
|
||||
|
||||
[feed-bob]
|
||||
proxy-type=none
|
||||
|
||||
[bob]
|
||||
overchan.*=1
|
||||
ctl=1
|
||||
|
||||
[feed-charlie]
|
||||
proxy-type=none
|
||||
|
||||
[charlie]
|
||||
overchan.*=1
|
||||
ctl=1
|
||||
|
||||
then restart srndv2
|
||||
|
||||
**TODO:** firewalling
|
||||
28
doc/postgres.md
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
Postgres on Debian (as root)
|
||||
|
||||
# install as root
|
||||
apt-get install --no-install-recommends postgresql postgresql-client
|
||||
|
||||
|
||||
Setting up postgres (as root)
|
||||
|
||||
# become postgres user
|
||||
su postgres
|
||||
# spawn postgres admin shell
|
||||
psql
|
||||
|
||||
You'll get a prompt, enter the following:
|
||||
|
||||
CREATE ROLE srnd WITH LOGIN PASSWORD 'srnd';
|
||||
CREATE DATABASE srnd WITH ENCODING 'UTF8' OWNER srnd;
|
||||
\q
|
||||
|
||||
For demo purposes we'll use these credentials.
|
||||
These are default values, please change them later.
|
||||
|
||||
## important
|
||||
|
||||
these credentials assume you are going to run using a user called `srnd`, if your username you plan to run the daemon as is different please change `srnd` to your username.
|
||||
|
||||
Now run it, [next](running.md)
|
||||
376
doc/protocol.md
Normal file
@@ -0,0 +1,376 @@
|
||||
Overchan is a newsgroup meant to be served on web frontends in an effort to create a decentralized imageboard. Moderation takes place on each frontend itself. Message and image transport is using MIME multipart messages and Base64 as encoding for Images. All messages need to be valid NNTP messages, the transport of messages need to follow NNTP specifications. It is possible to use an existing NNTP daemon like INN or to implement the NNTP sync part as well.
|
||||
|
||||
# Sync Protocol (NNTP)
|
||||
|
||||
## Article Format
|
||||
|
||||
### Monopart
|
||||
|
||||
Message without images can be sent without delimiting the message.
|
||||
|
||||
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From: anonymous <foo@bar.ano>
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
Message-ID: <pmc8xpmgyf2@foo.bar>
|
||||
Newsgroups: overchan.test
|
||||
Subject: none
|
||||
References: <referenced message-id>
|
||||
Path: hschan.ano
|
||||
X-Sage: optional
|
||||
|
||||
some visible message text
|
||||
|
||||
|
||||
### Multipart
|
||||
|
||||
This is necessary for posting files.
|
||||
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="abcdEFGH-1234"
|
||||
From: anonymous <foo@bar.ano>
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
Message-ID: <pmc8xpmgyf2@foo.bar>
|
||||
Newsgroups: overchan.test
|
||||
Subject: none
|
||||
References: <referenced message-id>
|
||||
Path: hschan.ano
|
||||
X-Sage: optional
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
--abcdEFGH-1234
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
some visible message text
|
||||
--abcdEFGH-1234
|
||||
Content-Type: image/jpeg; name="RosenFessel_LM_030-lg.jpg"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="RosenFessel_LM_030-lg.jpg"
|
||||
/9j/4AAQSkZJRgABAQAAAQABAAD//gA8Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJ
|
||||
SkcgSlBFRyB2NjIpLCBxdWFsaXR5ID0gMTAwCv/bAEMAAQEBAQEBAQEBAQEBAQEBAQEBAQEB
|
||||
[..]
|
||||
e3ykVkO1lOwlSMkfvDngbSOmRuqaDQo2Kqi5yUwfKPXkk8kAjIA5B4wPUVi8TKblJ1Oy969r
|
||||
ea8+nXc6I4WnFLROMVZRai1L4bK+vdfM/9k=
|
||||
--abcdEFGH-1234-
|
||||
Content-Type boundary="$IDENTIFIER"
|
||||
|
||||
|
||||
Where ``$identifier`` should be a rather long random string (at least 0-9, a-z, A-Z, - are allowed). The ``$identifier`` should not occur in the message text itself, so it usually begins with multiple - characters because these will never occur in base64. The content type ``multipart/mixed`` allows to have different parts inside a message body. The first part would be the actual message, the second part could be a Base64 encoded picture. See also: MIME
|
||||
|
||||
|
||||
In ~~2013~~ 2015 we can send UTF-8 messages, although this is not part of the old testament.
|
||||
|
||||
### Date
|
||||
|
||||
It is recommend to use ``UTC (+0000)`` as timezone for new messages. If a received message is not already in UTC, the date may be converted to UTC for display purposes.
|
||||
|
||||
### Message-ID: (see RFC 3977)
|
||||
|
||||
"A message-id MUST begin with "<", end with ">", and MUST NOT contain the latter except at the end."
|
||||
"A message-id MUST be between 3 and 250 octets in length."
|
||||
"A message-id MUST NOT contain octets other than printable US-ASCII characters."
|
||||
a possible valid message-id could be in the format <{random}{timestamp}@${frontend}> where:
|
||||
${random} == a random 10 char ascii value
|
||||
${timestamp} == the current unix_timestamp
|
||||
${frontend} == web.hschan.ano
|
||||
|
||||
Which would result in ``jbUdn73KxN1369733675@web.hschan.ano`` This format makes it easier to block massive spam/inapropiate content based on the frontend and a timespan.
|
||||
|
||||
### References
|
||||
|
||||
If reference is not given or empty, the message is considered an original (root) post.
|
||||
|
||||
### X-Sage
|
||||
|
||||
If ``X-Sage`` is given, the message shall not bump the corresponding thread.
|
||||
|
||||
## Transport Format
|
||||
|
||||
NNTP requires line endings with ``\r\n``
|
||||
|
||||
### Sending
|
||||
|
||||
if a line in the message body starts with `.` in needs another `.` prepended. the last line must be a single `.\r\n`
|
||||
|
||||
### Receiving:
|
||||
|
||||
If a line in the message body starts with `.` but is not `.\r\n` the `.` needs to be removed.
|
||||
|
||||
|
||||
# Frontend
|
||||
|
||||
## Postnumbers
|
||||
|
||||
The first ten characters of a sha1sum of field message-id. The probability for a unique post number (at time of generation) on a board with a maximum of 30k messages is:
|
||||
|
||||
(1-(1/16^10))^30000 = 0.99999997271515937221
|
||||
|
||||
In case of several message forgers exhaust obscure post numbers, it will become much more likely for a quote to be 'shadowed'.
|
||||
|
||||
There was a hash collision on October 13 2015, the post hash has been bumped from 10 to 18 bytes.
|
||||
|
||||
### Quotes
|
||||
|
||||
Quotes reference postnumbers and work across all boards on overchan. The comment field may contain serveral lines such as:
|
||||
|
||||
\>>postnumber
|
||||
|
||||
to quote someone.
|
||||
|
||||
Valid quotes match this regex: `>+ ?[0-9a-f]+`
|
||||
|
||||
#### Optional
|
||||
|
||||
* Resolve quotes to corresponding articles and append them to references - this will aid newsreaders.
|
||||
* Parse message IDs as quotes
|
||||
|
||||
## Implementations
|
||||
|
||||
Because of the decentralized nature of Overchan, many different entry points to using the service can exist. In the following we discuss different implementations all serving from the newsgroup 'overchan'.
|
||||
|
||||
### negromancy.ano
|
||||
|
||||
negromancy.ano uses `breaking-news`, a web frontend compiler for imageboards, pastebins, etc.
|
||||
|
||||
`breaking-news` consists of an Happstack application and a daemon that will generate static html from NNTP files. It depends on InterNetNews (INN) and a load balancer that can distinguish between POST and GET, preferably nginx. Furthermore it relies on imagemagick (mogrify) for generation of thumbnails. Hchloride are bindings to libsodium in haskell that breaking-news uses for singing messages.
|
||||
|
||||
It utilizes blaze-html for fast Html templating and happstack-lite for serving POST requests.
|
||||
|
||||
You can visit http://boards.negromancy.ano/
|
||||
|
||||
for browsing the imageboard.
|
||||
|
||||
#### GET request
|
||||
|
||||
nginx will serve a static html from dir.
|
||||
|
||||
#### POST request
|
||||
|
||||
nginx will reverse to the happstack web application which generates and sends a NNTP message to a local INN daemon. INNd will place the new article in dir and feed it to its configured peers. Pictures are encoded in base64 or base91a. Root posting will not work without attaching an image.
|
||||
|
||||
#### Generation of Html
|
||||
|
||||
The daemon will poll for new articles in dir. If new files are found, it generates 10 main pages ranging from 0.html to 9.html and a html each for any altered threads. For each new article the corresponding thread, starting with the original post, will be bumped to the first page (0.html). For new posts, corresponding pictures are created and 'thumbnailed' through mogrify.
|
||||
|
||||
### overchan.sfor.ano
|
||||
|
||||
overchan.sfor.ano uses SRNd, a complete NNTP server implemented in Python.
|
||||
|
||||
It provides a plugin interface (among other hook possibilities) which loads plug-in overchan and postman. Plug-in overchan is notified about new messages in `overchan.*` and creates static HTML files. Plug-in postman receives new messages via HTTP POST request and adds those messages to SRNd where they are send to configured outfeeds. It depends on a reverse proxy like nginx which delivers generated HTML files and proxies POST requests back to postman.
|
||||
|
||||
You can visit http://overchan.sfor.ano
|
||||
|
||||
for browsing the imageboard and ``git clone git://git.sfor.ano/SRNd.git`` for source.
|
||||
|
||||
#### GET request
|
||||
|
||||
nginx will serve a static html or image from dir.
|
||||
|
||||
#### POST request
|
||||
|
||||
nginx will proxy to postman which generates and delivers a NNTP message to SRNd which then will notify overchan plugin about the new message and also deliver it to its configured NNTP peers (which can run SRNd or another NNTPd software like INN). Pictures are encoded in base64.
|
||||
|
||||
#### Generation of Html
|
||||
|
||||
Plugin overchan is notified by SRNd about new articles and (re)generates `thread-$id.html` and its parent board with up to 10 root posts for each site. For each new article without `X-sage` header the corresponding thread will be bumped to the first page. For new posts, corresponding pictures are created and thumbnailed.
|
||||
|
||||
### NNTP News reader applications
|
||||
|
||||
Through the use of the standard MIME format, news reader applications like Mozilla Thunderbird can also read and post directly to the chan newsserver. Each chan will appear as a root post, while additional posts will appear as replies directly to the root post.
|
||||
|
||||
News readers have some features the chan software may not have: multiple attachments, non-image attachments, subject, posts referencing non-root posts, HTML text.
|
||||
|
||||
Open question: how should this be handled by the chan software for viewing?
|
||||
|
||||
# Extensions
|
||||
|
||||
## Control suggestion
|
||||
|
||||
A control suggestion is a single message containing lines with commands, message-ID and extra information separated by spaces.
|
||||
|
||||
### Commands
|
||||
|
||||
sticky: sticky this thread
|
||||
delete-x-all: delete all attachments from this article
|
||||
delete: delete the whole article
|
||||
|
||||
|
||||
### Format
|
||||
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From: anonymous <foo@bar.ano>
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
Message-ID: <h2cykk1lwlmuqao2qiy@foo.bar>
|
||||
Newsgroups: ctl
|
||||
Subject: none
|
||||
Path: censorship.fleet
|
||||
X-Sage: optional
|
||||
|
||||
delete-x-all <message-ID>
|
||||
delete <message-ID>
|
||||
delete <message-ID>
|
||||
|
||||
|
||||
Messages to control are separated by at least one line break.
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
Delete all attachments from message with ID ``message-ID``
|
||||
|
||||
delete-x-all <message-ID>
|
||||
|
||||
Please sticky thread with OP ``message-ID`` till UNIX timestamp ``1380000000``
|
||||
|
||||
sticky <message-ID> unix_timestamp 1380000000
|
||||
|
||||
|
||||
|
||||
|
||||
### Convention
|
||||
|
||||
We send control suggestions to newsgroup ``ctl``. Full deletion of a root post results in removal of corresponding thread.
|
||||
|
||||
### Signatures
|
||||
|
||||
As users give their secret key to the frontend they expect every form field to be verified on all ends. This includes the comment field and headers. In the following we suggest a protocol to sign optional headers.
|
||||
|
||||
We sign a SHA512 hash of the message body using primitive Ed25519 as defined by SUPERCOP and libsodium. Therefore this system does not inherit any collision resilience from Ed25519, a hash collision is a signature collision.
|
||||
|
||||
Signing M vs. Signing H(M)
|
||||
|
||||
method space time
|
||||
|
||||
S(M) O(n) O(n)
|
||||
|
||||
S(H(M)) O(1) O(n)
|
||||
|
||||
S: Sign
|
||||
H: Hash
|
||||
M: Message
|
||||
|
||||
|
||||
Input for block based hashing algorithms like SHA-512 can be streamed, only keeping a fixed blocked size in memory instead of all blocks. In case of SHA-512 these message blocks are 1024 bit and the hash to sign 512 bit. Optimized ``S(H(M))`` implementations require a constant amount memory as opposed to a linear requirement in ``S(M)``.
|
||||
|
||||
### Format for signing messages (RFC 822)
|
||||
|
||||
Outer headers start with ``Content-Type: message/rfc822`` when there are signed headers or at least an attachment,
|
||||
which requires ``Content-Type: multipart/mixed`` to be signed as well as an inner header.
|
||||
Otherwise you can use ``Content-Type: text/plain``, in which case you just sign the body.
|
||||
Outer headers include ``X-pubkey-ed25519`` and ``X-signature-ed25519-sha512``, inner headers need verification.
|
||||
``X-pubkey-ed25519`` is 64 characters long, 32 byte public key in base 16: ``Base16(PK)``
|
||||
``X-signature-ed25519-sha512`` is 128 characters long, 64 byte signature in base 16: ``Base16(S(SK,H(M)))``
|
||||
The signed message equals body of the outer message. It begins at first inner header (in this example ``Content-Type: text/plain``) and includes the inner body. Lines are separated by ``<CRLF>``.
|
||||
Please include a ``Content-Type`` header in the inner message as suggested by RFC822.
|
||||
|
||||
Symbol Function
|
||||
|
||||
Base16 function that will take an arbitrary amount of octets and encode them to Base 16 with character set "0123456789abcdef"
|
||||
SK 64 bytes secret key
|
||||
PK 32 bytes public key, can be generated from signSeedKeypair(take32(SK))
|
||||
M message body
|
||||
H function that will hash an arbitrary amount of octets using SHA-512, returning 64 bytes
|
||||
S(SK,M) function that will sign an arbitrary amount of octets M using Ed25519 with secret key SK, returning only the first 64 bytes
|
||||
take32 function that takes any amount of binary data and returns the first 32 bytes
|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
Content-Type: message/rfc822; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From: anonymous <foo@bar.ano>
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
Message-ID: <h2cykk1lwlmuqao2qiy@foo.bar>
|
||||
Newsgroups: ctl
|
||||
Subject: none
|
||||
Path: censorship.fleet
|
||||
X-pubkey-ed25519: 37c16fa40c2bade813b53b65107a064d02becfa5635acf3241003a61cb137ea3
|
||||
X-signature-ed25519-sha512: a850ccd788d71ed19de8dfa061b9f1f4f506810a01ed1391433e893a3e6305b4944168760d97f2517bcfe786aef1ccfc34fb7bb1b77531 82aebf2bdd0303150f
|
||||
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
|
||||
delete-x-all <message-ID>
|
||||
delete <message-ID>
|
||||
|
||||
delete <message-ID
|
||||
|
||||
|
||||
In this example header Date needs verification, too.
|
||||
The following part is signed:
|
||||
|
||||
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
|
||||
delete-x-all <message-ID>
|
||||
delete <message-ID>
|
||||
|
||||
delete <message-ID
|
||||
|
||||
|
||||
Above example in octets:
|
||||
|
||||
Content-Type: text/plain; charset=UTF-8\\r\\nDate: Thu, 02 May 2013 12:16:44 +0000\\r\\n\\r\\ndelete-x-all <message-ID>\\r\\ndelete <message-ID>\\r\\n\\r\\ndelete <message-ID>
|
||||
|
||||
## RPC
|
||||
Remote procedure calls can be sent via ``ctl`` or on a group basis by using the group ``ctl.overchan.*``, where * is the group for which you want to execute a certain operation.
|
||||
|
||||
### Default format
|
||||
The default format uses the MIME type ``text/plain`` where the first line of the body opens an array with ``[`` the next line is the name of the procedure you want to call, and on the lines following you can add one or more parameters. Each of these lines is terminated with `,` and indention can be added as well. The arry is closed with `]`.
|
||||
|
||||
#### Exapmple
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From: anonymous <foo@bar.ano>
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
Message-ID: <h2cykk1lwlmuqao2qiy@foo.bar>
|
||||
Newsgroups: ctl.overchan.foo
|
||||
Subject: RPC
|
||||
Path: hschan.ano
|
||||
|
||||
[
|
||||
setSetting,
|
||||
bumplimit,
|
||||
350,
|
||||
]
|
||||
|
||||
|
||||
### JSON RPC
|
||||
If the MIME type is specified as ``application/json`` the body is interpreted as [JSON RPC](http://json-rpc.org/).
|
||||
|
||||
#### Exapmple
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From: anonymous <foo@bar.ano>
|
||||
Date: Thu, 02 May 2013 12:16:44 +0000
|
||||
Message-ID: <h2cykk1lwlmuqao2qiy@foo.bar>
|
||||
Newsgroups: ctl.overchan.foo
|
||||
Subject: RPC
|
||||
Path: hschan.ano
|
||||
|
||||
{"method": "setSetting", "params": ["bumplimit", "350"], "id": null}
|
||||
|
||||
### Additional details
|
||||
As described above, muliple RPC's can be sent via the multipart format. It is also expected that these articles are signed.
|
||||
|
||||
# Glossary
|
||||
|
||||
## chan specific
|
||||
|
||||
### root post
|
||||
original post
|
||||
|
||||
### OP
|
||||
original post
|
||||
|
||||
### thread
|
||||
a collection of messages starting with the original post followed by messages referencing it ordered by date
|
||||
|
||||
### bump
|
||||
newest post will be shown first with corresponding thread
|
||||
|
||||
### sticky
|
||||
thread is temporarily 'bumped' by the frontend and sticks there regardless of newer posts
|
||||
37
doc/redis.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# configuring redis database backend
|
||||
|
||||
|
||||
0) Install redis
|
||||
|
||||
Redis 3.x or higher is required
|
||||
|
||||
0.A) debian/ubuntu
|
||||
|
||||
# apt update
|
||||
# apt install redis-server
|
||||
|
||||
0.B) redhat
|
||||
|
||||
# yum install redis
|
||||
|
||||
0.C) from source
|
||||
|
||||
* see http://redis.io/download
|
||||
|
||||
|
||||
|
||||
1) Configuration
|
||||
|
||||
In srnd.ini the database sections should look like this:
|
||||
|
||||
[database]
|
||||
type=redis
|
||||
schema=single
|
||||
host=localhost
|
||||
port=6379
|
||||
user=
|
||||
password=
|
||||
|
||||
2) Run the daemon
|
||||
|
||||
* see the [next step](running.md)
|
||||
39
doc/running.md
Normal file
@@ -0,0 +1,39 @@
|
||||
## Running
|
||||
|
||||
After you have [built the daemon](build.md) and [configured the database](database.md) you can run the daemon.
|
||||
|
||||
|
||||
check out the nntpchan repo and build the daemon if you already haven't
|
||||
|
||||
git clone https://github.com/majestrate/nntpchan
|
||||
cd nntpchan
|
||||
./build.sh
|
||||
|
||||
set up the daemon:
|
||||
|
||||
./srndv2 setup
|
||||
|
||||
generate admin keys, don't loose them.
|
||||
|
||||
./srndv2 tool keygen
|
||||
|
||||
add yourself as admin by adding your ``public key`` to the ``frontend`` section of ``srnd.ini``
|
||||
|
||||
...
|
||||
[frontend]
|
||||
enable=1
|
||||
admin_key=yourpublickeygoeshere
|
||||
... # leave the rest of the config values alone for now
|
||||
|
||||
|
||||
|
||||
run it:
|
||||
|
||||
./srndv2 run
|
||||
|
||||
|
||||
Now open the browser up to http://127.0.0.1:18000/
|
||||
|
||||
To access the mod panel go to the [mod panel](http://127.0.0.1:18000/mod/) and use your ``private key`` to log in
|
||||
|
||||
Now read about [peering](feeds.md)
|
||||
3
doc/srnd.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# srnd.ini
|
||||
|
||||
todo: document this file
|
||||
77
install.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
root=$(readlink -e $(dirname $0))
|
||||
|
||||
prefix="/opt/nntpchan"
|
||||
|
||||
help_text="usage: $0 [--prefix /opt/nntpchan] [-q|--quiet] [-r|--rebuild] [--disable-redis]"
|
||||
|
||||
# check for help flags first
|
||||
for arg in $@ ; do
|
||||
case $arg in
|
||||
-h|--help)
|
||||
echo $help_text
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
_next=""
|
||||
want_rebuild="0"
|
||||
want_quiet="0"
|
||||
build_args=""
|
||||
|
||||
# check for main flags
|
||||
for arg in $@ ; do
|
||||
case $arg in
|
||||
-q|--quiet)
|
||||
want_quiet="1"
|
||||
;;
|
||||
-r|--rebuild)
|
||||
want_rebuild="1"
|
||||
;;
|
||||
--prefix)
|
||||
_next="prefix"
|
||||
;;
|
||||
--prefix=*)
|
||||
prefix=$(echo $arg | cut -d'=' -f2)
|
||||
;;
|
||||
--disable-redis)
|
||||
build_args="$build_args --disable-redis"
|
||||
;;
|
||||
*)
|
||||
if [ "X$_next" == "Xprefix" ] ; then
|
||||
# set prefix
|
||||
prefix="$arg"
|
||||
_next=""
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
_cmd() {
|
||||
if [ "X$want_quiet" == "X1" ] ; then
|
||||
$@ &> /dev/null
|
||||
else
|
||||
$@
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "X$want_rebuild" == "X1" ] ; then
|
||||
_cmd echo "rebuilding daemon";
|
||||
_cmd $root/build.sh $build_args
|
||||
fi
|
||||
|
||||
if [ ! -e $root/srndv2 ] ; then
|
||||
_cmd echo "building daemon"
|
||||
# TODO: use different GOPATH for root?
|
||||
_cmd $root/build.sh $build_args
|
||||
fi
|
||||
|
||||
|
||||
_cmd mkdir -p $prefix
|
||||
_cmd mkdir -p $prefix/webroot/thm
|
||||
_cmd mkdir -p $prefix/webroot/img
|
||||
_cmd cp -f $root/srndv2 $prefix/srndv2
|
||||
_cmd cp -rf $root/{doc,contrib,certs} $prefix/
|
||||
_cmd echo "installed to $prefix"
|
||||