1
0
Fork 0

Compare commits

...

109 Commits

Author SHA1 Message Date
Alexander Andreev 70b45a628b
Version set to 24.16.1. 2024-04-16 18:39:52 +04:00
Alexander Andreev 4c72141932
Fixed <s></s> tag on an about page in a section about ukrainian language. 2024-04-16 18:38:59 +04:00
Alexander Andreev 12f53ba427
Version set to 24.16.0. 2024-04-16 18:30:06 +04:00
Alexander Andreev e1bc31eaa1
Updated lastmod for /about in sitemap.xml. 2024-04-16 18:29:31 +04:00
Alexander Andreev 9edacf1c8f
Updated an About page. 2024-04-16 18:28:46 +04:00
Alexander Andreev 53097234e5
A referal link to Tinkoff was added. 2024-04-16 17:03:06 +04:00
Alexander Andreev ffb9eaf356
Removed a notice about not being able to send a reply, even though, it may still happen. 2024-04-16 16:59:21 +04:00
Alexander Andreev eabe0cd1bd
Recently commented out everything about XMPP was completely erased. Don't think about setting a Jabber server again. 2024-04-08 04:15:16 +04:00
Alexander Andreev 244098253d
TL;DR about services was removed. 2024-04-08 04:13:44 +04:00
Alexander Andreev 235de5f04c
What I like -> What I liked. Also updated its content. 2024-04-08 04:11:35 +04:00
Alexander Andreev e37428d758
Fuck me! Silent Hunter 3 wasn't on the list! 2024-04-08 03:10:58 +04:00
Alexander Andreev b32ad2613f
Holy shit, how could I forget? I spent so much time in Battlefield: Vietnam playing with bots... Also recalled Delta Force: Black Hawk Down, great game. 2024-04-08 03:02:17 +04:00
Alexander Andreev 60efecc307
A link to Tinkoff was changed. 2024-03-14 17:35:55 +04:00
Alexander Andreev 0d854063d5
Comment out Jabber. 2024-03-14 17:33:29 +04:00
Alexander Andreev 9d1af110bd
Updated version to 24.10.0 2024-03-04 02:07:04 +04:00
Alexander Andreev 4505cc03d4
Updated sitemap.xml. 2024-03-04 02:06:05 +04:00
Alexander Andreev 6871b68a13
Update index.pug. 2024-03-04 02:05:05 +04:00
Alexander Andreev 240540d75b
Updated about.pug. 2024-03-04 02:04:32 +04:00
Alexander Andreev ac5a4662f3
Added a copyright sign to a footer for fuck's sake. 2024-03-03 21:33:28 +04:00
Alexander Andreev 6775b05d70
In article.pug cache ToClientTimezone() to a var for futher use. 2024-03-03 21:32:11 +04:00
Alexander Andreev 6dc826b0ca
Updated a PGP key from 2E873A7831FF0BB640ACEDA5D22A817D95815393 to 739850CD5051DE554368709225969B23DCB5CA34. 2024-03-03 19:38:22 +04:00
Alexander Andreev b0b0e8a77a
Updated index's meta description. 2024-03-03 19:03:31 +04:00
Alexander Andreev a2204947a0
Removed an extra space before .ygg. 2024-03-03 18:59:41 +04:00
Alexander Andreev 4634e76572
Remove QIWI from Donation. 2024-02-28 17:06:49 +04:00
Alexander Andreev 6fd2a45569
Updated year in a footer. 2024-02-26 02:28:34 +04:00
Alexander Andreev 047f63d083
Simplified stuff page. 2024-02-25 20:01:53 +04:00
Alexander Andreev 8b46076669
Set version to 24.7.0. 2024-02-18 18:42:26 +04:00
Alexander Andreev d0a5bfc285
Updated About page. 2024-02-18 03:03:24 +04:00
Alexander Andreev d4e07a2256
I turned 31 some time ago, time to update it here. :) 2024-02-15 03:07:12 +04:00
Alexander Andreev d4c414785a
Added a link to a web map of a Minecraft world. 2024-02-15 03:06:27 +04:00
Alexander Andreev ac02190659
A proper check for a service status. 2023-12-16 04:27:32 +04:00
Alexander Andreev 34d469319d
Set timeout 1 second for GatherStatus(). 2023-12-16 04:27:03 +04:00
Alexander Andreev 86fdf05322
Version set to 23.50.0. 2023-12-16 03:34:39 +04:00
Alexander Andreev dbdf8ba62b
Updated Minecraft info. 2023-12-16 03:34:11 +04:00
Alexander Andreev 331781b711
Updated versions for mccl and httpprocprobed. 2023-12-16 02:48:32 +04:00
Alexander Andreev 4ec84b5f1e
Updated service names. 2023-12-16 02:46:31 +04:00
Alexander Andreev 319471fab3
Updated x/image and mattn/go-sqlite3 packages. 2023-11-10 01:47:39 +04:00
Alexander Andreev e5e07af896
Fixed title attrib for a jabber link on about page. 2023-10-30 04:03:40 +04:00
Alexander Andreev a0c1272b3c
Version set to 23.44.0. 2023-10-30 03:56:19 +04:00
Alexander Andreev 9962251279
Changed About page a little. 2023-10-30 03:55:06 +04:00
Alexander Andreev 5539cd7357
Added mccl on stuff page. 2023-10-30 03:54:47 +04:00
Alexander Andreev e705aa80a5
In mindflow admin changed grid template. 2023-09-25 18:49:26 +04:00
Alexander Andreev b0b1730699
Added a .quote class for mindflow. 2023-09-25 17:10:07 +04:00
Alexander Andreev 000b5d1dce
In Makefile from target run a -guestbook-owner argument was removed because it was hardcoded lately. 2023-09-25 16:58:08 +04:00
Alexander Andreev cbaa2f32b4
Added a check for an empty line when check for a quotation in mindflow.pug. 2023-09-25 16:57:20 +04:00
Alexander Andreev 24cf81a3ce
Moved a link to a footer of a post. Removed "Link:". Add span element if there is no URL, because justify-content: space-between is used, and without an element a date will move to the left with display: flex, even with text-align: right. 2023-09-25 16:55:42 +04:00
Alexander Andreev 5bc4f13c38
Added qouting formatting in Mindflow. 2023-09-25 03:21:49 +04:00
Alexander Andreev 134ed23450
Added PREFIX in Makefile and in PKGBUILD in package(). 2023-09-25 02:17:12 +04:00
Alexander Andreev 33cd1dc3b8
Well, actually... Let's hardcode guestbook owner. :) 2023-09-25 01:56:54 +04:00
Alexander Andreev a3525418f1
In about.pug: liquidsoap replaced by ezstream. 2023-09-25 01:13:14 +04:00
Alexander Andreev fb7459c021
Added a tip for that quotation exists in a guestbook. 2023-09-25 00:34:55 +04:00
Alexander Andreev 85a3a9692e
A big revamp for mindflow and RSS. First of all, now RSS is 100% valid and has actual links instead of just a link to a post in a mindflow. Also, on mindflow page each post that has a URL field set has it displayed as Link: ... . 2023-09-25 00:23:06 +04:00
Alexander Andreev 906f73c8a6
Refactored flags in main.go. 2023-09-24 21:33:08 +04:00
Alexander Andreev a464a11ea8
In errorXXX.pug fixed tabulation to spaces. 2023-09-24 20:51:51 +04:00
Alexander Andreev 03e7c478e0
GetArticleMetadata() was replaced by Metadata public slice. 2023-09-24 20:44:03 +04:00
Alexander Andreev 948715d8eb
Fill Metadata slice in init(). Removed GetArticleMetadata. A slice instead was made public. 2023-09-24 20:43:36 +04:00
Alexander Andreev 9e33fa359b
Nah, let's remove bin/, so executable will be built every time. 2023-09-24 20:42:30 +04:00
Alexander Andreev fe87114fe0
In Article HTTP handler a loging for web.GetArticle() was changed. 2023-09-24 20:00:49 +04:00
Alexander Andreev 48e7a86312
Part of GetArticle() for loading an article from a file was moved out to init() func. 2023-09-24 20:00:17 +04:00
Alexander Andreev 72b09218f8
In web/articles.go made use of a constructor. Also, since a constructor returns a pointer, map also now stores a pointer to Article. 2023-09-24 19:05:22 +04:00
Alexander Andreev 7f17ebd2c5
In Article struct switched positions of Title and Date fields. 2023-09-24 19:03:29 +04:00
Alexander Andreev 0695aa46b3
For Article added a consturctor func New(). 2023-09-24 19:02:43 +04:00
Alexander Andreev 1c3f0c7b2c
Added b32.i2p address in nginx.conf. 2023-09-24 18:47:21 +04:00
Alexander Andreev 5b57592370
In Makefile a bin/ prefix was added to ${TARGET}, so make could see an executable and not rebuild it every time. 2023-09-23 21:51:49 +04:00
Alexander Andreev caf096c0f6
In rss.pug fixed date formatting. 2023-09-23 21:49:09 +04:00
Alexander Andreev 20729899b0
In Makefile long lines was wrapped. Also removed .txt extension. 2023-09-23 21:48:40 +04:00
Alexander Andreev 2b32422754
In Makefile's install target fixed copypasta mistyping. 2023-09-23 20:00:03 +04:00
Alexander Andreev cb08e6e334
In Makefile's run target replaced arg names by theirs new long names. 2023-09-23 19:58:47 +04:00
Alexander Andreev 6895c1c0a6
For whatever reason Go doesn't fill r.URL.Scheme. So let's get it directly from Scheme header that is being set in nginx's proxy_set_header Scheme $scheme. 2023-09-23 19:57:53 +04:00
Alexander Andreev 98e948f982
In rss.pug fixed link tag. Jade treats it like an HTML's link self-closing tag. 2023-09-23 19:56:12 +04:00
Alexander Andreev a315679847
On stuff page: updated version and release date for kwh-cost. 2023-09-23 05:24:11 +04:00
Alexander Andreev 90ce3c74f0
Oh, actually, a whole directory for licenses is supposed to be removed on uninstallation. 2023-09-23 05:22:27 +04:00
Alexander Andreev 38dadee5af
On stuff page: updated description for PiggyBank. 2023-09-23 05:13:43 +04:00
Alexander Andreev f572f4b3e5
On stuff page: commented out auto-claimer-vkpl because it stopped working and I don't bother to fix it; Updated version and release date for httpr. 2023-09-23 05:11:08 +04:00
Alexander Andreev 1aaf2e8474
Added my name and surname in a footer. 2023-09-23 04:46:25 +04:00
Alexander Andreev db34c5d249
Made cmd arguments long. 2023-09-23 04:37:48 +04:00
Alexander Andreev ff70cd8ade
Fixed a comment for GetArticleMetadata() func. It is actually is being sorted by ID, not data. 2023-09-23 04:25:32 +04:00
Alexander Andreev fbb4389065
In GetArticle() func removed unnecessary else {} nesting. 2023-09-23 04:23:33 +04:00
Alexander Andreev 69493f50aa
In web.go removed a comment for how to install a Jade compiler. 2023-09-23 04:20:31 +04:00
Alexander Andreev 35ac352490
Added missing license file for Share Tech Mono font I use. 2023-09-23 04:18:36 +04:00
Alexander Andreev d373ad0f35
In Makefile un-/install targets added a LICENSE file for a font used, but commented out. 2023-09-23 04:13:39 +04:00
Alexander Andreev e992e6906a
In Makefile un-/install targets added a LICENSE file, but commented out. 2023-09-23 04:11:18 +04:00
Alexander Andreev 9fd750a99b
In Makefile made use of PREFIX var. 2023-09-23 04:10:37 +04:00
Alexander Andreev 3a3db1a673
Version set to 23.38.0. 2023-09-23 04:04:01 +04:00
Alexander Andreev 8caad6ca3e
In Makefile fixed .PHONY and ${TARGET}. In a web/*.pug.go target added ifeq to check if jade compiler is already installed. 2023-09-23 04:03:28 +04:00
Alexander Andreev 7c17d7400b
Added additional build flags in FLAGS var. 2023-09-23 04:01:48 +04:00
Alexander Andreev 24c5f59200
In Makefile set DSTDIR to an empty string. 2023-09-23 03:59:17 +04:00
Alexander Andreev f93c732ada
In go.mod and go.sum updated dependencies. 2023-09-23 03:55:30 +04:00
Alexander Andreev 27c336035b
In PKGBUILD go version was specified to be >=1.17. 2023-09-23 03:55:01 +04:00
Alexander Andreev 798012b9cb
Removed unnecessary options from PKGBUILD. SQLite is part of a base package, so no need in specifing it here. And also no need to specify the package explicitly in provides= and conflicts= options. 2023-09-23 03:54:14 +04:00
Alexander Andreev 1628a26ed7
Added CGO_*FLAGS env vars in PKGBUILD. 2023-09-23 03:51:25 +04:00
Alexander Andreev 35b48d29e6
In main.go made use of handler's Error func and in Error() func added missing WriteHeader(). 2023-08-13 02:17:47 +04:00
Alexander Andreev 4523e5a622
Oh, I forgot that inline styling and in a head tag are forbidden. Moving out to a file. 2023-08-13 01:46:15 +04:00
Alexander Andreev ffbc027d64
Add missing 404 response code. 2023-08-13 01:41:58 +04:00
Alexander Andreev 4a29a9754b
Added leading slash to path to a PGP pubkey. 2023-08-13 01:25:05 +04:00
Alexander Andreev 4fe528f141
Fixed rel='canonical' href. 2023-08-13 01:21:16 +04:00
Alexander Andreev c21d117120
Added missing leading slashes for rss links. 2023-08-13 01:20:45 +04:00
Alexander Andreev 8a278c6052
Fixed position of a background image on an index page. 2023-08-13 00:03:29 +04:00
Alexander Andreev 91d7d79109
Added auto-claimer-vkpl. Updated versions of justcaptcha and httpr. 2023-08-12 23:58:48 +04:00
Alexander Andreev b63d5e1ac0
Add space between links in a table. 2023-08-12 23:58:13 +04:00
Alexander Andreev 16ae8d4dca
Show Go back link on an error page. 2023-08-12 23:57:55 +04:00
Alexander Andreev e1cf7187df
Replaced HTTP server code with a newest one. 2023-08-12 23:53:26 +04:00
Alexander Andreev a6bec0db75
Made use of httpr.Router.Sub() functionality. 2023-08-12 23:52:52 +04:00
Alexander Andreev 6fe6c856cd
Show Go back on error page, need to pass a referer URL for it. 2023-08-12 23:51:26 +04:00
Alexander Andreev 87453e160d
Version set to 23.32.0. 2023-08-12 22:59:12 +04:00
Alexander Andreev a5acbe4029
Updated justcaptcha dependency. 2023-08-12 22:58:54 +04:00
Alexander Andreev 78e5695f53
Set min-height so a background image will be at the bottom of a window. 2023-08-06 04:19:42 +04:00
Alexander Andreev 7ee5939d39
In main.go removed a space between httpr.Handler() statements for mindflow and its category. 2023-07-29 18:08:02 +04:00
Alexander Andreev 5802410fa4
GetArticlesMetadata() -> GetArticleMetadata() 2023-07-29 17:59:36 +04:00
40 changed files with 468 additions and 281 deletions

93
LICENSE.ShareTechMono.txt Normal file
View File

@ -0,0 +1,93 @@
Copyright (c) 2012, Carrois Type Design, Ralph du Carrois (post@carrois.com www.carrois.com), with Reserved Font Name 'Share'
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -2,33 +2,42 @@ TARGET=dwelling-home
SYSDDIR_=${shell pkg-config systemd --variable=systemdsystemunitdir}
SYSDDIR=${SYSDDIR_:/%=%}
DESTDIR=/
DESTDIR:=
PREFIX:=/usr/local
VERSION=23.29.0
VERSION=24.16.1
FLAGS:=-buildmode=pie -modcacherw -mod=readonly -trimpath
LDFLAGS=-ldflags "-s -w -X main.version=${VERSION}" -tags osusergo,netgo
all: web/*.pug.go ${TARGET}
.PHONY: run install uninstall clean
.PHONY: ${TARGET}
${TARGET}:
go build -o bin/$@ ${LDFLAGS} cmd/$@/main.go
${TARGET}: web/*.pug.go
go build -o bin/$@ ${LDFLAGS} ${FLAGS} cmd/$@/main.go
web/*.pug.go: web/templates/*.pug
ifeq (,$(wildcard $(shell go env GOPATH)/bin/jade))
go install github.com/Joker/jade/cmd/jade@latest
endif
go generate web/web.go
run:
bin/${TARGET} -l 127.0.0.1:18123 -db . -ce 10m -gbo Arav -gbp 10
bin/${TARGET} -listen 127.0.0.1:18123 -database-path . -captcha-expiry 10m \
-guestbook-page-size 10
install:
install -Dm 0755 bin/${TARGET} ${DESTDIR}usr/bin/${TARGET}
install -Dm 0755 bin/${TARGET} ${DESTDIR}${PREFIX}/bin/${TARGET}
install -Dm 0644 init/systemd.service ${DESTDIR}${SYSDDIR}/${TARGET}.service
# install -Dm 0644 LICENSE ${DESTDIR}/usr/share/licenses/${TARGET}/LICENSE
# install -Dm 0644 LICENSE.RobotoCondensed.txt \
# ${DESTDIR}/usr/share/licenses/${TARGET}/LICENSE.RobotoCondensed
# install -Dm 0644 LICENSE.ShareTechMono.txt \
# ${DESTDIR}/usr/share/licenses/${TARGET}/LICENSE.ShareTechMono
uninstall:
rm ${DESTDIR}usr/bin/${TARGET}
rm ${DESTDIR}${PREFIX}/bin/${TARGET}
rm ${DESTDIR}${SYSDDIR}/${TARGET}.service
# rm -r ${DESTDIR}/usr/share/licenses/${TARGET}
clean:
rm -f bin/${TARGET}

View File

@ -1,25 +1,26 @@
# Maintainer: Alexander "Arav" Andreev <me@arav.su>
pkgname=dwelling-home
pkgver=23.29.0
pkgver=24.16.1
pkgrel=1
pkgdesc="Arav's dwelling / Home"
arch=('i686' 'x86_64' 'arm' 'armv6h' 'armv7h' 'aarch64')
url="https://git.arav.su/Arav/dwelling-home"
license=('MIT')
depends=('sqlite')
makedepends=('go')
provides=('dwelling-home')
conflicts=('dwelling-home')
makedepends=('go>=1.17')
source=("https://git.arav.su/Arav/dwelling-home/archive/v${pkgver}.tar.gz")
md5sums=('SKIP')
build() {
cd "$srcdir/$pkgname"
export GOPATH="$srcdir"/gopath
make VERSION=$pkgver DESTDIR="$pkgdir/"
export CGO_CPPFLAGS="${CPPFLAGS}"
export CGO_CFLAGS="${CFLAGS}"
export CGO_CXXFLAGS="${CXXFLAGS}"
export CGO_LDFLAGS="${LDFLAGS}"
make VERSION=$pkgver DESTDIR="$pkgdir/" PREFIX="/usr"
}
package() {
cd "$srcdir/$pkgname"
make DESTDIR="$pkgdir/" install
make DESTDIR="$pkgdir/" PREFIX="/usr" install
}

View File

@ -5,11 +5,9 @@ import (
"fmt"
"log"
"net/http"
"net/netip"
"os"
"os/signal"
"path"
"strings"
"syscall"
"time"
@ -22,12 +20,14 @@ import (
var version string
var showVersion *bool = flag.Bool("v", false, "show version")
var listenAddress *string = flag.String("l", "/var/run/dwelling-home/sock", "listen address (ip:port|unix_path)")
var captchaExpiry *time.Duration = flag.Duration("ce", 10*time.Minute, "CAPTCHA expiry (e.g. 5m, 60s)")
var guestbookOwner *string = flag.String("gbo", "Admin", "name of a guestbook owner")
var guestbookPageSize *int64 = flag.Int64("gbp", 60, "size of a guestbook page")
var databasesPath *string = flag.String("db", "/var/lib/dwelling-home", "path to a directory where to store DB files")
var (
showVersion = flag.Bool("v", false, "show version")
listenAddress = flag.String("listen", "/var/run/dwelling-home/sock", "listen address (ip:port|unix_path)")
captchaExpiry = flag.Duration("captcha-expiry", 10*time.Minute, "CAPTCHA expiry (e.g. 5m, 60s)")
guestbookOwner = "Arav"
guestbookPageSize = flag.Int64("guestbook-page-size", 60, "size of a guestbook page")
databasesPath = flag.String("database-path", "/var/lib/dwelling-home", "path to a directory where to store DB files")
)
func main() {
flag.Parse()
@ -39,25 +39,6 @@ func main() {
log.SetFlags(log.Llongfile)
var network string
if !strings.ContainsRune(*listenAddress, ':') {
network = "unix"
defer os.Remove(*listenAddress)
} else {
ap, err := netip.ParseAddrPort(*listenAddress)
if err != nil {
log.Fatalln(err)
} else if !ap.IsValid() {
log.Fatalln(*listenAddress, "is not valid")
}
if ap.Addr().Is4() {
network = "tcp4"
} else if ap.Addr().Is6() {
network = "tcp6"
}
}
guestbookDB, err := gb.NewSQLiteDB(path.Join(*databasesPath, "guestbook.sqlite"))
if err != nil {
log.Fatalln(err)
@ -70,12 +51,12 @@ func main() {
}
defer mindflowDB.Close()
hand := dwhttp.NewHandlers(*captchaExpiry, *guestbookOwner, *guestbookPageSize, guestbookDB, mindflowDB)
hand := dwhttp.NewHandlers(*captchaExpiry, guestbookOwner, *guestbookPageSize, guestbookDB, mindflowDB)
r := httpr.New()
r.NotFoundHandler = func(w http.ResponseWriter, _ *http.Request) {
web.ErrorXXX("/ Not Found", "", "", http.StatusNotFound, w)
r.NotFoundHandler = func(w http.ResponseWriter, r *http.Request) {
dwhttp.Error(w, http.StatusNotFound, "", "", r.Referer())
}
r.ServeStatic("/assets/*filepath", web.Assets())
@ -96,32 +77,34 @@ func main() {
captchaApi := dwhttp.NewCaptchaApiHandlers(*captchaExpiry)
r.Handler(http.MethodPost, "/api/captcha", captchaApi.New)
r.Handler(http.MethodPost, "/api/captcha/:id", captchaApi.Solve)
r.Handler(http.MethodGet, "/api/captcha/:id/image", captchaApi.Image)
s := r.Sub("/api/captcha")
s.Handler(http.MethodPost, "/", captchaApi.New)
s.Handler(http.MethodPost, "/:id", captchaApi.Solve)
s.Handler(http.MethodGet, "/:id/image", captchaApi.Image)
guestbookApi := dwhttp.NewGuestbookApiHandlers(*guestbookOwner, *guestbookPageSize, guestbookDB)
guestbookApi := dwhttp.NewGuestbookApiHandlers(guestbookOwner, *guestbookPageSize, guestbookDB)
r.Handler(http.MethodPost, "/api/guestbook", guestbookApi.New)
r.Handler(http.MethodPatch, "/api/guestbook/:id", guestbookApi.Edit)
r.Handler(http.MethodDelete, "/api/guestbook/:id", guestbookApi.Delete)
r.Handler(http.MethodPost, "/api/guestbook/:id/reply", guestbookApi.Reply)
r.Handler(http.MethodPatch, "/api/guestbook/:id/reply", guestbookApi.EditReply)
r.Handler(http.MethodDelete, "/api/guestbook/:id/reply", guestbookApi.DeleteReply)
s = r.Sub("/api/guestbook")
s.Handler(http.MethodPost, "/", guestbookApi.New)
s.Handler(http.MethodPatch, "/:id", guestbookApi.Edit)
s.Handler(http.MethodDelete, "/:id", guestbookApi.Delete)
s.Handler(http.MethodPost, "/:id/reply", guestbookApi.Reply)
s.Handler(http.MethodPatch, "/:id/reply", guestbookApi.EditReply)
s.Handler(http.MethodDelete, "/:id/reply", guestbookApi.DeleteReply)
mindflowApi := dwhttp.NewMindflowApiHandlers(mindflowDB)
r.Handler(http.MethodPost, "/api/mindflow", mindflowApi.NewPost)
r.Handler(http.MethodPatch, "/api/mindflow/:id", mindflowApi.EditPost)
r.Handler(http.MethodDelete, "/api/mindflow/:id", mindflowApi.DeletePost)
r.Handler(http.MethodPost, "/api/mindflow/category", mindflowApi.NewCategory)
r.Handler(http.MethodPatch, "/api/mindflow/category/:id", mindflowApi.EditCategory)
r.Handler(http.MethodDelete, "/api/mindflow/category/:id", mindflowApi.DeleteCategory)
s = r.Sub("/api/mindflow")
s.Handler(http.MethodPost, "/", mindflowApi.NewPost)
s.Handler(http.MethodPatch, "/:id", mindflowApi.EditPost)
s.Handler(http.MethodDelete, "/:id", mindflowApi.DeletePost)
s.Handler(http.MethodPost, "/category", mindflowApi.NewCategory)
s.Handler(http.MethodPatch, "/category/:id", mindflowApi.EditCategory)
s.Handler(http.MethodDelete, "/category/:id", mindflowApi.DeleteCategory)
srv := dwhttp.NewHttpServer(r)
if err := srv.Start(network, *listenAddress); err != nil {
if err := srv.Start(*listenAddress); err != nil {
log.Fatalln(err)
}
defer func() {

View File

@ -3,7 +3,7 @@ server {
listen 8090; # Tor I2P
listen [300:a98d:d6d0:8a08::f]:80; # Yggdrasil
server_name arav.su www.arav.su arav.i2p moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion;
server_name arav.su www.arav.su arav.i2p t42fkp6zp5dfqywantq3zp427ig3q2onrmfv246tyaztpg4ckb5a.b32.i2p moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion;
access_log /var/log/nginx/dwelling/dwelling.log main if=$nolog;

10
go.mod
View File

@ -3,19 +3,19 @@ module git.arav.su/Arav/dwelling-home
go 1.17
require (
git.arav.su/Arav/justcaptcha v0.0.0-20230506005225-406fb66c17ca
git.arav.su/Arav/justcaptcha/v2 v2.1.0
git.arav.su/Arav/justguestbook v1.3.2
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386
github.com/pkg/errors v0.9.1
)
require (
github.com/fogleman/gg v1.3.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
golang.org/x/image v0.9.0 // indirect
golang.org/x/image v0.14.0 // indirect
)
require (
git.arav.su/Arav/httpr v0.2.1
github.com/mattn/go-sqlite3 v1.14.17 // indirect
git.arav.su/Arav/httpr v0.3.2
github.com/mattn/go-sqlite3 v1.14.18 // indirect
)

26
go.sum
View File

@ -1,27 +1,26 @@
git.arav.su/Arav/httpr v0.2.1 h1:wtago8iYOqeoyOvio1uhMItXaTHXiBVfsshtYWSURhw=
git.arav.su/Arav/httpr v0.2.1/go.mod h1:z0SVYwe5dBReeVuFU9QH2PmBxICJwchxqY5OfZbeVzU=
git.arav.su/Arav/justcaptcha v0.0.0-20230506005225-406fb66c17ca h1:keam4p+hYktoRNNparpacUS5LMjzFs4ERwHuV/IXqAw=
git.arav.su/Arav/justcaptcha v0.0.0-20230506005225-406fb66c17ca/go.mod h1:eXjBHk26MLvfRZrf3MY29HCIN/YlICklXby0JVkG4oA=
git.arav.su/Arav/httpr v0.3.2 h1:a+ifu+9+FnQe6p/Kd4kgTDKAFN6zBOJjBTMjbAuHxVk=
git.arav.su/Arav/httpr v0.3.2/go.mod h1:z0SVYwe5dBReeVuFU9QH2PmBxICJwchxqY5OfZbeVzU=
git.arav.su/Arav/justcaptcha/v2 v2.1.0 h1:EFerW2mP60rDczu1mPbJb7DiDeAQOcw83/KiWcxCOKs=
git.arav.su/Arav/justcaptcha/v2 v2.1.0/go.mod h1:Ntab6TUAqCo/H9LSWOd4IQ9ANnp8G1PEygXtORcdTOY=
git.arav.su/Arav/justguestbook v1.3.2 h1:B1AzS14dW3bVlp0Qj6pu1PrJlWaPK1mplmx3UNBcxo4=
git.arav.su/Arav/justguestbook v1.3.2/go.mod h1:Umo/AzSOKu+OU+03V7/QQ6m6N0nXyeRAGOZT4P5ol98=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E=
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4=
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -44,7 +43,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@ -6,7 +6,9 @@ After=network-online.target
Type=simple
Restart=on-failure
DynamicUser=yes
ExecStart=/usr/bin/dwelling-home -l /var/run/dwelling-home/sock -db /var/lib/dwelling-home -ce 10m -gbo Arav -gbp 60
ExecStart=/usr/bin/dwelling-home -listen /var/run/dwelling-home/sock \
-database-path /var/lib/dwelling-home -captcha-expiry 10m \
-guestbook-page-size 60
ReadOnlyPaths=/
@ -20,18 +22,33 @@ LockPersonality=true
MemoryDenyWriteExecute=true
NoNewPrivileges=true
PrivateDevices=true
PrivateTmp=true
PrivateUsers=true
ProcSubset=pid
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=noaccess
ProtectSystem=strict
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=~@clock
SystemCallFilter=~@cpu-emulation
SystemCallFilter=~@debug
SystemCallFilter=~@module
SystemCallFilter=~@mount
SystemCallFilter=~@obsolete
SystemCallFilter=~@privileged
SystemCallFilter=~@raw-io
SystemCallFilter=~@reboot
SystemCallFilter=~@swap
[Install]
WantedBy=multi-user.target

View File

@ -7,9 +7,9 @@ import (
"time"
"git.arav.su/Arav/httpr"
"git.arav.su/Arav/justcaptcha/pkg/captcha"
"git.arav.su/Arav/justcaptcha/pkg/captcha/inmemdb"
"git.arav.su/Arav/justcaptcha/pkg/dwcaptcha"
captcha "git.arav.su/Arav/justcaptcha/v2"
"git.arav.su/Arav/justcaptcha/v2/dwcaptcha"
"git.arav.su/Arav/justcaptcha/v2/inmemdb"
)
type CaptchaApiHandlers struct {

View File

@ -6,8 +6,8 @@ import (
"strings"
"git.arav.su/Arav/httpr"
"git.arav.su/Arav/justcaptcha/pkg/captcha"
"git.arav.su/Arav/justcaptcha/pkg/captcha/inmemdb"
captcha "git.arav.su/Arav/justcaptcha/v2"
"git.arav.su/Arav/justcaptcha/v2/inmemdb"
"git.arav.su/Arav/justguestbook"
)
@ -29,7 +29,8 @@ func (h *GuestbookApiHandlers) New(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
if !inmemdb.Solve(captcha.ID(r.FormValue("captcha_id")), captcha.Answer(r.FormValue("captcha_answer"))) {
Error(w, http.StatusForbidden, "Wrong answer given.", "Here's your message:"+r.FormValue("message"))
Error(w, http.StatusForbidden, "Wrong answer given.",
"Here's your message:"+r.FormValue("message"), r.Referer())
return
}
@ -42,13 +43,15 @@ func (h *GuestbookApiHandlers) New(w http.ResponseWriter, r *http.Request) {
entry, err = justguestbook.NewEntry(r.FormValue("name"), message,
r.FormValue("website"), r.FormValue("hide_website") != "")
if err != nil {
Error(w, http.StatusInternalServerError, err.Error(), "Here's your message:"+r.FormValue("message"))
Error(w, http.StatusInternalServerError, err.Error(),
"Here's your message:"+r.FormValue("message"), r.Referer())
return
}
}
if err = h.db.NewEntry(entry); err != nil {
Error(w, http.StatusInternalServerError, err.Error(), "Here's your message:"+r.FormValue("message"))
Error(w, http.StatusInternalServerError, err.Error(),
"Here's your message:"+r.FormValue("message"), r.Referer())
return
}

View File

@ -42,7 +42,7 @@ func (h *MindflowApiHandlers) NewPost(w http.ResponseWriter, r *http.Request) {
category.ID, _ = strconv.ParseInt(r.FormValue("category"), 10, 64)
}
post, err = mindflow.NewPost(*category, r.FormValue("title"), r.FormValue("body"))
post, err = mindflow.NewPost(*category, r.FormValue("title"), r.FormValue("url"), r.FormValue("body"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@ -51,7 +51,7 @@ func (h *MindflowApiHandlers) NewPost(w http.ResponseWriter, r *http.Request) {
if err = h.db.NewPost(post); err != nil {
msg := strings.Join([]string{"Title:", r.FormValue("title"), "| Body:", r.FormValue("body")}, " ")
Error(w, http.StatusInternalServerError, err.Error(), msg)
Error(w, http.StatusInternalServerError, err.Error(), msg, r.Referer())
return
}
@ -67,6 +67,7 @@ func (h *MindflowApiHandlers) EditPost(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
body := cleanupNewlines(r.FormValue("body"))
url := r.FormValue("url")
category.ID, err = strconv.ParseInt(r.FormValue("category"), 10, 64)
if err != nil {
@ -74,7 +75,7 @@ func (h *MindflowApiHandlers) EditPost(w http.ResponseWriter, r *http.Request) {
return
}
post, err = mindflow.NewPost(category, r.FormValue("title"), body)
post, err = mindflow.NewPost(category, r.FormValue("title"), url, body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return

View File

@ -5,12 +5,15 @@ import (
"log"
"net"
"net/http"
"net/netip"
"os"
"strings"
"time"
)
type HttpServer struct {
s http.Server
s http.Server
addr net.Addr
}
func NewHttpServer(r http.Handler) *HttpServer {
@ -20,7 +23,23 @@ func NewHttpServer(r http.Handler) *HttpServer {
Handler: r}}
}
func (s *HttpServer) Start(network, address string) error {
func (s *HttpServer) Start(address string) error {
var network string
if !strings.ContainsRune(address, ':') {
network = "unix"
} else {
ap, err := netip.ParseAddrPort(address)
if err != nil {
return err
}
if ap.Addr().Is4() {
network = "tcp4"
} else if ap.Addr().Is6() {
network = "tcp6"
}
}
listener, err := net.Listen(network, address)
if err != nil {
return err
@ -30,6 +49,8 @@ func (s *HttpServer) Start(network, address string) error {
os.Chmod(address, 0777)
}
s.addr = listener.Addr()
go func() {
if err = s.s.Serve(listener); err != nil && err != http.ErrServerClosed {
log.Fatalln(err)
@ -43,6 +64,10 @@ func (s *HttpServer) Stop() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if s.addr.Network() == "unix" {
defer os.Remove(s.addr.String())
}
if err := s.s.Shutdown(ctx); err != nil {
return err
}

View File

@ -12,8 +12,8 @@ import (
"git.arav.su/Arav/dwelling-home/pkg/servicestat"
"git.arav.su/Arav/dwelling-home/pkg/util"
"git.arav.su/Arav/dwelling-home/web"
"git.arav.su/Arav/justcaptcha/pkg/captcha/inmemdb"
"git.arav.su/Arav/justcaptcha/pkg/dwcaptcha"
"git.arav.su/Arav/justcaptcha/v2/dwcaptcha"
"git.arav.su/Arav/justcaptcha/v2/inmemdb"
"git.arav.su/Arav/justguestbook"
)
@ -49,7 +49,7 @@ func (h *Handlers) Privacy(w http.ResponseWriter, r *http.Request) {
func (h *Handlers) Stuff(w http.ResponseWriter, r *http.Request) {
web.Stuff("/ Stuff", util.GetServiceByHost(r.Host, util.ServiceGit),
util.GetServiceByHost(r.Host, util.ServiceFiles), web.GetArticlesMetadata(), w)
util.GetServiceByHost(r.Host, util.ServiceFiles), web.Metadata, w)
}
func (h *Handlers) Mindflow(w http.ResponseWriter, r *http.Request) {
@ -70,13 +70,13 @@ func (h *Handlers) Mindflow(w http.ResponseWriter, r *http.Request) {
func (h *Handlers) MindflowAdmin(w http.ResponseWriter, r *http.Request) {
posts, err := h.mindflowDB.Posts()
if err != nil {
Error(w, http.StatusInternalServerError, err.Error(), "failed to load posts")
Error(w, http.StatusInternalServerError, err.Error(), "failed to load posts", r.Referer())
return
}
categories, err := h.mindflowDB.Categories()
if err != nil {
Error(w, http.StatusInternalServerError, err.Error(), "failed to load categories")
Error(w, http.StatusInternalServerError, err.Error(), "failed to load categories", r.Referer())
return
}
@ -103,9 +103,9 @@ func (h *Handlers) About(w http.ResponseWriter, r *http.Request) {
func (h *Handlers) Article(w http.ResponseWriter, r *http.Request) {
name := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]
artcl, err := web.GetArticle(name)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
artcl := web.GetArticle(name)
if artcl == nil {
http.Error(w, "an article doesn't exist", http.StatusNotFound)
return
}
@ -153,7 +153,7 @@ func (h *Handlers) GuestbookAdmin(w http.ResponseWriter, r *http.Request) {
entriesCount, _ := h.guestbookDB.Count()
entries, err := h.guestbookDB.Entries(1, entriesCount)
if err != nil {
Error(w, http.StatusInternalServerError, err.Error(), "cannot load gb")
Error(w, http.StatusInternalServerError, err.Error(), "cannot load gb", r.Referer())
return
}
for _, entry := range entries {
@ -168,8 +168,14 @@ func (h *Handlers) RSS(w http.ResponseWriter, r *http.Request) {
if err != nil {
return
}
var scheme string
if r.Header.Get("Scheme") != "" {
scheme = r.Header.Get("Scheme")
} else {
scheme = "http"
}
web.RSS(r.URL.Scheme+"://"+r.Host, "Arav", posts, r, w)
web.RSS(scheme+"://"+r.Host, "Arav", posts, r, w)
}
func FaviconIco(w http.ResponseWriter, r *http.Request) {
@ -187,8 +193,9 @@ func SitemapXml(w http.ResponseWriter, r *http.Request) {
w.Write(data)
}
func Error(w http.ResponseWriter, code int, reason, message string) {
web.ErrorXXX("/ "+http.StatusText(code), reason, message, code, w)
func Error(w http.ResponseWriter, code int, reason, message, referer string) {
w.WriteHeader(code)
web.ErrorXXX("/ "+http.StatusText(code), reason, message, referer, code, w)
}
func cleanupNewlines(text string) (out string) {

View File

@ -9,12 +9,18 @@ import (
type Article struct {
ID int64
Title string
Date time.Time
Title string
Description string
Body []byte
}
func New(body, meta []byte) (article *Article, err error) {
article = &Article{Body: body}
err = article.ParseMetadata(meta)
return
}
func (artcl *Article) ParseMetadata(data []byte) error {
lines := bytes.Split(data, []byte{'\n'})
if len(lines) != 4 {

View File

@ -122,7 +122,8 @@ func (s *SQLiteMindflow) NewPost(post *mindflow.Post) error {
}
defer tx.Rollback()
r, err := tx.Stmt(stmtPostNew).Exec(post.Category.ID, post.Date.UTC().Unix(), post.Title, post.Body)
r, err := tx.Stmt(stmtPostNew).Exec(post.Category.ID, post.Date.UTC().Unix(),
post.Title, post.URL, post.Body)
if err != nil {
return err
}
@ -144,7 +145,8 @@ func (s *SQLiteMindflow) EditPost(post *mindflow.Post) error {
}
defer tx.Rollback()
_, err = tx.Stmt(stmtPostEdit).Exec(post.Category.ID, post.Title, post.Body, post.ID)
_, err = tx.Stmt(stmtPostEdit).Exec(post.Category.ID, post.Title, post.URL,
post.Body, post.ID)
if err != nil {
return err
}
@ -187,7 +189,8 @@ func (s *SQLiteMindflow) Posts() (posts []mindflow.Post, err error) {
var post mindflow.Post
var date_unix int64
if err = rows.Scan(&post.ID, &post.Category.ID, &post.Category.Name, &date_unix, &post.Title, &post.Body); err != nil {
if err = rows.Scan(&post.ID, &post.Category.ID, &post.Category.Name,
&date_unix, &post.Title, &post.URL, &post.Body); err != nil {
return nil, err
}

View File

@ -2,5 +2,6 @@ UPDATE OR REPLACE `post`
SET
`category_id` = ?,
`title` = ?,
`url` = ?,
`body` = ?
WHERE `post_id` = ?;

View File

@ -4,6 +4,7 @@ SELECT
`category`.`name` AS `category`,
`post`.`date`,
`post`.`title`,
`post`.`url`,
`post`.`body`
FROM `post`
LEFT JOIN `category`

View File

@ -1,4 +1,4 @@
INSERT INTO `post`
(`category_id`, `date`, `title`, `body`)
(`category_id`, `date`, `title`, `url`, `body`)
VALUES
(?, ?, ?, ?);
(?, ?, ?, ?, ?);

View File

@ -15,6 +15,7 @@ CREATE TABLE IF NOT EXISTS `post` (
`category_id` INTEGER NOT NULL,
`date` INTEGER NOT NULL,
`title` TEXT NOT NULL,
`url` TEXT NOT NULL DEFAULT "",
`body` TEXT NOT NULL,
PRIMARY KEY (`post_id`),
FOREIGN KEY (`category_id`)

View File

@ -5,6 +5,8 @@ import (
"fmt"
"strings"
"time"
"git.arav.su/Arav/dwelling-home/pkg/util"
)
type Category struct {
@ -24,10 +26,11 @@ type Post struct {
Category Category
Date time.Time
Title string
URL string
Body string
}
func NewPost(category Category, title, body string) (*Post, error) {
func NewPost(category Category, title, url, body string) (*Post, error) {
if title == "" || body == "" {
return nil, errors.New("empty title or body is not allowed")
}
@ -35,6 +38,7 @@ func NewPost(category Category, title, body string) (*Post, error) {
Category: category,
Date: time.Now().UTC(),
Title: title,
URL: url,
Body: body}, nil
}
@ -44,6 +48,22 @@ func (p *Post) PostID() string {
return fmt.Sprint(name, "-", p.Date.UTC().Format("20060102-150405"))
}
func (p *Post) PostURL(host string, rss bool) string {
if p.URL != "" {
if p.URL[0] == ':' {
lastColon := strings.IndexByte(p.URL[1:], ':')
service := p.URL[1 : lastColon+1]
return strings.Replace(p.URL, p.URL[:lastColon+2],
util.GetServiceByHost(host, service), 1)
} else if rss && p.URL[0] == '/' {
return util.GetServiceByHost(host, "") + p.URL
}
} else if p.URL == "" && rss {
return util.GetServiceByHost(host, "") + "/mindflow#" + p.PostID()
}
return p.URL
}
type Mindflow interface {
NewPost(post *Post) error
EditPost(post *Post) error

View File

@ -3,6 +3,7 @@ package servicestat
import (
"encoding/json"
"net/http"
"time"
)
type ServiceList map[string]bool
@ -11,7 +12,7 @@ func GatherStatus(url string) (lst ServiceList, err error) {
rq, _ := http.NewRequest(http.MethodGet, url, nil)
rq.Header.Set("Content-Type", "application/json")
cl := &http.Client{}
cl := &http.Client{Timeout: 1 * time.Second}
r, err := cl.Do(rq)
if err != nil {
return lst, err

View File

@ -2,6 +2,7 @@ package web
import (
"embed"
"log"
"sort"
"strings"
"time"
@ -17,7 +18,7 @@ const (
//go:embed articles
var articlesFS embed.FS
var articles map[string]article.Article = make(map[string]article.Article)
var articles map[string]*article.Article = make(map[string]*article.Article)
// ArticleMetadata holds date, title and URL of an article used in articles list
// on the Stuff page.
@ -28,11 +29,46 @@ type ArticleMetadata struct {
URL string
}
// GetArticlesMetadata returns a slice of metadata that is sorted by date
func GetArticlesMetadata() (meta []ArticleMetadata) {
for urlid, article := range articles {
var Metadata []ArticleMetadata
meta = append(meta,
func GetArticle(name string) *article.Article {
if artcl, ok := articles[name]; ok {
return artcl
}
return nil
}
func init() {
//// Load articles
entries, _ := articlesFS.ReadDir("articles")
for _, entry := range entries {
if strings.HasSuffix(entry.Name(), articleFileExtension) {
name := strings.TrimSuffix(entry.Name(), articleFileExtension)
meta, err := articlesFS.ReadFile("articles/" + name + articleMetaExtension)
if err != nil {
log.Fatalln("an article \"", name, "\" cannot be read:", err)
}
md, err := articlesFS.ReadFile("articles/" + entry.Name())
if err != nil {
log.Fatalln("a metadata for an article \"", name, "\" cannot be read:", err)
}
articles[name], err = article.New(markdown.ToHTML(md, nil, nil), meta)
if err != nil {
log.Fatalln("an article \"", name, "\" cannot be parsed:", err)
}
}
}
//// Fill and sort metadata slice
for urlid, article := range articles {
Metadata = append(Metadata,
ArticleMetadata{
ID: article.ID,
Date: article.Date,
@ -40,44 +76,9 @@ func GetArticlesMetadata() (meta []ArticleMetadata) {
URL: "stuff/article/" + urlid})
}
sort.Slice(meta, func(i, j int) bool {
return meta[i].ID > meta[j].ID
sort.Slice(Metadata, func(i, j int) bool {
return Metadata[i].ID > Metadata[j].ID
})
return
}
func GetArticle(name string) (*article.Article, error) {
if artcl, ok := articles[name]; ok {
return &artcl, nil
} else {
meta, err := articlesFS.ReadFile("articles/" + name + articleMetaExtension)
if err != nil {
return nil, err
}
md, err := articlesFS.ReadFile("articles/" + name + articleFileExtension)
if err != nil {
return nil, err
}
artcl := article.Article{
Body: markdown.ToHTML(md, nil, nil)}
artcl.ParseMetadata(meta)
articles[name] = artcl
return &artcl, nil
}
}
func init() {
entries, _ := articlesFS.ReadDir("articles")
for _, entry := range entries {
if strings.HasSuffix(entry.Name(), articleFileExtension) {
GetArticle(strings.TrimSuffix(entry.Name(), articleFileExtension))
}
}
articlesFS = embed.FS{}
}

7
web/assets/css/error.css Normal file
View File

@ -0,0 +1,7 @@
#error {
font-size: 3.5rem;
line-height: 5rem;
text-align: center;
margin: 6rem 0; }
#error h1 { font-size: 8rem; }

View File

@ -1,6 +1,6 @@
body {
height: 75vh;
margin-top: 25vh; }
margin-top: 25vh;
min-height: 75vh; }
header { position: relative; }

View File

@ -85,6 +85,8 @@ tr :is(th, td) {
tr :is(th, td):not(:last-child) { padding-right: .5rem; }
tr a:not(:last-child) { margin-right: .25rem; }
.highlighted { color: var(--primary-color); }
html {
@ -98,6 +100,7 @@ body {
font-size: 1.1rem;
margin: 0 auto;
max-width: 960px;
min-height: 100vh;
width: 98%; }
@media screen and (min-width: 1280px) {

View File

@ -4,6 +4,9 @@ button:not(:last-child) { padding-right: 1rem; }
article header a { color: var(--text-color); }
article p.quote { font-style: italic; }
article footer {
text-align: right;
display: flex;
justify-content: space-between;
padding: 0; }

View File

@ -17,17 +17,16 @@ form#add {
display: grid;
gap: .5rem;
grid-template-areas:
"c c"
"t t"
"b b"
"a a";
grid-template-columns: 1fr 1fr;
"b b b b"
"c t u a";
grid-template-columns: repeat(1fr, 3) .25fr;
max-width: 100%;
min-width: 100%;
width: 100%; }
form#add select { grid-area: c; }
form#add input[name="title"] { grid-area: t; }
form#add input[name="url"] { grid-area: u; }
form#add textarea[name="body"] { grid-area: b; }
form#add button[type="submit"] { grid-area: a; }
@ -35,13 +34,16 @@ form.edit {
display: grid;
gap: .5rem;
grid-template-areas:
"b b"
"e d";
grid-template-columns: 1fr 1fr;
"b b b b b"
"c t u e d";
grid-template-columns: 1fr 1fr 1fr .25fr .25fr;
max-width: 100%;
min-width: 100%;
width: 100%; }
form.edit textarea { grid-area: b; }
form.edit select[name="category"] { grid-area: c; }
form.edit input[name="title"] { grid-area: t; }
form.edit input[name="url"] { grid-area: u; }
form.edit input[name="edit"] { grid-area: e; }
form.edit input[name="delete"] { grid-area: d; }

View File

@ -7,6 +7,7 @@ function edit_post(e) {
let data = new URLSearchParams();
data.append("category", get_field(e.target, "category"))
data.append("title", get_field(e.target, "title"))
data.append("url", get_field(e.target, "url"))
data.append("body", get_field(e.target, "body"))
fetch(`/api/mindflow/${get_field(e.target, "post-id")}`, {method: "PATCH", body: data})
.catch(e => console.log(e))

View File

@ -2,11 +2,11 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://arav.su/</loc>
<lastmod>2023-03-02</lastmod>
<lastmod>2024-03-04</lastmod>
</url>
<url>
<loc>https://arav.su/stuff</loc>
<lastmod>2023-07-04</lastmod>
<lastmod>2024-03-04</lastmod>
</url>
<url>
<loc>https://arav.su/stuff/article/rpi_root_on_external_drive</loc>
@ -34,7 +34,7 @@
</url>
<url>
<loc>https://arav.su/about</loc>
<lastmod>2023-07-04</lastmod>
<lastmod>2024-04-16</lastmod>
</url>
<url>
<loc>https://arav.su/guestbook</loc>

View File

@ -15,7 +15,7 @@ block nav
h1 About
mixin isServiceUp(header, service)
if (services[service])
if v, ok := services[service]; ok && v
h3.service-up= header
else
h3.service-down= header
@ -24,12 +24,11 @@ block content
:go:func About(title, files_site string, services servicestat.ServiceList)
section#about-me
h2 Me
p #[span.highlighted Who am I?] My name is Alexander Andreev. I'm a russian guy of age 30 who likes tinkering with computers.
p #[span.highlighted Why am I doing all of this?] Machines are up 24/7 anyway, so let they do some useful work.
p #[span.highlighted Why am I almost &ldquo;doxxing&rdquo; myself?] Yes, my real first and last names, and age are here, and since I self-host you can get my city as well. And I simply don't see this as a problem. :|
p #[span.highlighted Who am I?] My name is Alexander Andreev. I'm a russian guy of age 31 who likes tinkering with computers.
p #[span.highlighted Why am I doing all of this?] Machines are up 24/7 anyway, so why not?
p #[span.highlighted Why am I almost &ldquo;doxxing&rdquo; myself?] Yes, my real first and last names and age are here, and since I self-host you can get my city as well. And I simply don't see this as a problem. :|
p #[span.highlighted Why particularly that slogan?] I just wanted sort of a slogan that would fit under the logo and this was the first thing came on mind. I actually like it. Don't you think of your websites as of very special place of your own? Of course you do. :) And who we are if not the wanderers who are looking for something in the vastness of Intenet? xD And yes, it's a pain in the ass to make it fit under logo across different browsers. That was the moment when I found out that different browsers render text differently.
p #[span.highlighted Why English only?] I want this place to be accessible for a wide audience, and English happen to be todays lingua franca. Second, to practice English. And third, I'm lazy to maintain two versions of the website, neither see a good reason for that.
p Contact information and banners are #[a(href='#contacts') at the bottom of this page]. Yes, I totally agree with you not wanting to add my banner since I don't have a link page myself, neither participate in any webring. :) Well, it's way easier to make a banner than a links page. :)
p #[span.highlighted Why English only?] I want this place to be accessible for a wide audience and English happen to be todays lingua franca, and to practice the language of course.
p Now a little break for...
section#my-cat
h2 My kot Boris :3
@ -54,39 +53,36 @@ block content
h3 What I know
h4 Human languages
p #[span.highlighted English] is my main foreign language and I think that I know it quite well, but every time I reread what I wrote here I constantly catch cringe vibes. xD I have a nice pronunciation (my teacher once said so :)) and tend to British non-rhotic variant. Of course I end up with a mix of all the flavours of different dialects. What I struggle from is a lack of speaking practice and vocabulary is also still a problem.
p #[span.highlighted Ukrainian (Українська)] is a special case. :) Russian and ukrainian are related languages, so mutually understandable (must be), yet many russians are struggling to understand it, and I don't know why. It is just a matter of putting some little effort to negatiate it. I never learnt it, aside from reading it here and there, and looking up some words in a dictionary, and especially throughout past #[s 8]9 years I saw enough material to learn it to a decent level of understanding and some speaking.
p Агась, нiколи спецiйно не вчив українську, користував перекладач тiльки як словник, за цi #[s вiсiм] вже дев'ять рокiв було досить матерiалiв. :) P.S.: Слава Українi у складi Росiї! :)
p #[span.highlighted English] is my main foreign language and I think that I know it quite well, but every time I reread what I wrote here I constantly catch cringe vibes. xD I have a nice pronunciation (my teacher once said so :)) and tend to British non-rhotic variant. Of course I end up with a mix of all the flavours of different dialects. What I struggle from is a lack of speaking practice and vocabulary is still a problem as well.
p #[span.highlighted Ukrainian (Українська)] is a special case. :) Russian and ukrainian are related languages, so are mutually understandable (at least must be), yet many russians are struggling to understand it, and I genuinely don't get why. It is just a matter of putting some little effort to negatiate it. I never learnt it, aside from reading it here and there, and looking up some words in a dictionary, and especially throughout past #[s 8] #[s 9] 10 years I saw enough material to learn it to a decent level of understanding and some speaking.
p Агась, нiколи спецiйно не вчив українську, користував перекладач тiльки як словник, за цi #[s вiс ] #[s вже дев'ять] десять рокiв було досить матерiалiв. :) P.S.: Слава Українi у складi Росiї! :)
p I like learning languages, but me being a lazy fuck won't let me learn something up to a reasonable level. I ended up with being able to +- read some languages, like norwegian, german, polish, french, japanese (hiragana + some yet not forgotten kanji). So, now I main only English.
h4 Computer languages
p #[span.highlighted For programming and scripting:] Python, Go, JavaScript, and Bash for now are most used by me. Later I used or tasted: Pascal, Delphi, C#, C, C++, Java, PHP. And wrote hello worlds in some others like LISP and Haskell.
p #[span.highlighted Markup and declarative:] SQL (SQLite3, MariaDB), HTML5, CSS3, LaTeX, Markdown, XML, and JSON.
p And I don't know what else to put here. :^)
h3 What I like
h3 What I liked
h4 Anime
p Ghost in the Shell, Shaman King, Hellsing, Steins;Gate, Cowboy Beebop, Ergo Proxy, Jin-Rou, Black Lagoon, Jojo's Bizzare Adventures, Spice and Wolf, Konosuba, Demon Slayer: Kimetsu no Yaiba
h4 Films
p Boss Nigger (The Black Bounty Killer) (1974), Movies with Jackie Chan, Blade Runner (1982), WarGames (1983), Robocop (1987), Talk Radio (1988), Stargate (1994), Hackers (1995), Johnny Mnemonic (1995), Contact (1997), Matrix (1999, 2003), Snatch (2000), Oldboy (2003), The Day After Tomorrow (2004), The Gingerdead Man (2005), Lucky Number Slevin (2006), I Am Legend (2007), Valhalla Rising (2009), Filth (2013), Mandariinid (2013), Gingerdead Man vs. Evil Bong (2013), Who am I (2014), Arrival (2016), Contratiempo (2016), Wandering Earth (2019), Everything Everywhere All at Once (2022), Dungeons & Dragons: Honor Among Thieves (2023), Wandering Earth 2 (2019)
p Paths of Glory (1957), Boss Nigger (The Black Bounty Killer) (1974), Movies with Jackie Chan, Blade Runner (1982), WarGames (1983), Robocop (1987), Talk Radio (1988), Stargate (1994), Hackers (1995), Johnny Mnemonic (1995), Contact (1997), Matrix (1999, 2003), Snatch (2000), Oldboy (2003), The Day After Tomorrow (2004), Alpha Dog (2005), Constantine (2005), The Gingerdead Man (2005), Lucky Number Slevin (2006), 99 francs (2007), I Am Legend (2007), Inglourious Basterds (2009), Valhalla Rising (2009), The Guard (2011), Filth (2013), Mandariinid (2013), Gingerdead Man vs. Evil Bong (2013), Gone Girl (2014), Who am I (2014), Arrival (2016), Contratiempo (2016), Wandering Earth (2019), Wandering Earth 2 (2019), Greyhound (2020), I Care A Lot (2020), The Greatest Beer Run Ever (2022), Everything Everywhere All at Once (2022), Dungeons & Dragons: Honor Among Thieves (2023)
h4 TV shows
p X-Files (1993&mdash;2002), Lost (2004&mdash;2010), Stargate: SG-1 (1997&mdash;2007), Stargate: Atlantis (2004&mdash;2009), The Shivering Truth (2018&mdash;2020), Два холма (Two Hills) (2022), Narcos (2015&mdash;2017)
p These lists aren't complete, will extend when remember or find something.
p I actually don't watch much, and if I watch I go for a marathon, and if only I take a break in the middle of a show, then that break could last for years. xD And if I download some film it could sit for years, as it was with Valhalla Rising, it was waiting for me to watch for 3 fucking years. xD Oh, what made me to watch it? An one and a half hour long power outage. xD
p I found my way of watching films and anime. Watching it with my favorite streamers! xD
h4 Games for SEGA Mega Drive
p Not a lot of games I have played.
p Bubba'n'Stix, Battletoads, Granada, Demolition Man, Road Rash, Doom Troopers - The Mutant Chronicles, The Lost Vikings, Ghostbusters, Mig-29 Fighter Pilot.
h4 Games for PC
p Grand Theft Auto: Vice City, Half-Life (all), StarCraft, Diablo 2, Far Cry (2004), Grand Theft Auto: San Andreas, Boiling Point: Road to Hell, Portal, Freelancer, F.E.A.R., S.T.A.L.K.E.R., Grand Theft Auto 4, Lineage 2, The Elder Scrolls V: Skyrim, The Walking Dead, The Wolf Among Us, Payday 2, The Witcher (1st, 2nd, 3rd didn't finished yet), Minecraft, Terraria, Starbound, Euro Truck Simulator 2, Mount &amp; Blade: Warband, Papers, Please, Insurgency, Elite: Dangerous, theHunter: Call of the Wild, American Truck Simulator, Rocket League, Sea Of Thieves.
p Grand Theft Auto: Vice City, Half-Life (all), StarCraft, Diablo 2, Far Cry (2004), Battlefield: Vietnam, Delta Force: Black Hawk Down, Silent Hunter 3, Grand Theft Auto: San Andreas, Boiling Point: Road to Hell, Portal, Freelancer, F.E.A.R., S.T.A.L.K.E.R., Grand Theft Auto 4, Lineage 2, The Elder Scrolls V: Skyrim, Battlefield 3, The Walking Dead, The Wolf Among Us, Payday 2, The Witcher (1st, 2nd, 3rd didn't finished yet), Minecraft, Terraria, Starbound, Euro Truck Simulator 2, Mount &amp; Blade: Warband, Papers, Please, Insurgency, Elite: Dangerous, theHunter: Call of the Wild, American Truck Simulator, Rocket League, Sea Of Thieves.
p I'm CMDR Arav in Elite: Dangerous. My <a href="https://www.edsm.net/en/user/profile/id/22541/cmdr/Arav" rel="noopener noreferrer">EDSM profile</a>.
p I play TruckersMP mod for Euro Truck Simulator 2 and American Truck Simulator. Nickname is Arav with a tag [RU64].
h4 Music
p My favorites that I like almost fully are Falkenbach, Korpiklaani, Sólstafir, Lacrimosa, Enigma, Röyksopp, Nagrobki, Burzum, maybe I forgot to mention something. You can see what I like on #[a(href=files_site+"/music") file share]. I have a tendency to listen to the same music for a long time, so only way for me to know about other music are online-radios and WEBM threads on IBs. :)
p You can see what I like in #[a(href=files_site+"/music") a file share].
section#servers-summary
h2 My servers
p I have two of them, the first one is a #[a(href='https://www.raspberrypi.org/products/raspberry-pi-3-model-b/' rel='nofollow noreferrer') Raspberry Pi 3 rev. B] single board computer and the second one is a laptop. Yeah, not quite impressive, but they do their work just fine.
p Laptop is Acer Packard Bell TE69CX that has a 2 core Intel Pentium 2117U 1.8GHz and 10GB RAM (2GB + 8GB), the system disk is a 120GB SSD and the other one is 2TB HDD where all the shit I have is stored. I've replaced my good old 500GB disk with 2TB one, since it became a little too tight, now it is a system disk for Raspberry Pi. Everything that have just a bit of importantance to me is backed up, encrypted and stored in the clouds. :)
p #[span.highlighted TL;DR about services.] Laptop runs BIND9 via DNSCrypt-proxy (master), a network file share, a public file upload service, a seedbox, a HTTP public file share, TeamSpeak 3, Mumble, I2P, an internet-radio, git server, ClamAV for email server, a web-server, and a database. Raspberry Pi 3 runs BIND9 via DNSCrypt-proxy (slave), #[s a Tor relay], an email server, and a XMPP server.
p Also now I have a helper VPS with a 1 core 2.2GHz CPU and 512M RAM, and a 10GB disk I use as a slave DNS server for my domain and a postfix relay to send a mail.
section#servers-photos
div.columns.figs
figure
@ -102,7 +98,7 @@ block content
p.center That are available for everyone.
div.columns
div
+isServiceUp("Internet-radio", "liquidsoap")
+isServiceUp("Internet-radio", "radio")
p
a(href='https://radio.arav.su') radio.arav.su
| .
@ -111,8 +107,7 @@ block content
a(href='http://radio.arav.i2p') i2p
| .
a(href='http://[300:a98d:d6d0:8a08::e]') ygg
p Runs using Liquidsoap through Icecast, which goes through NGiNX. I broadcast almost everything I have. Sorry, but I'm too lazy to make some kind of broadcasting program to stream so I just randomise the playlist and throw new music there from time to time.
p This project grew from MPD I used to stream music over LAN for myself. Then I let it out and placed a player on my Neocities website. Then Icecast was added to see if there are listeners. I wasn't happy on how MPD was nearly overloading CPU, and later, after moving the radio off to a laptop, MPD was replaced by Liquidsoap.
p Runs using Ezstream through Icecast which goes through NGiNX. Ezstream fetches a playlist from a self-written solution. I broadcast almost everything I have. I'm too lazy to make some kind of broadcasting program to stream so I just randomise the playlist and throw new music there from time to time.
div
+isServiceUp("File share", "dwelling-files")
p
@ -123,7 +118,7 @@ block content
a(href='http://files.arav.i2p') i2p
| .
a(href='http://[300:a98d:d6d0:8a08::d]') ygg
p There you'll find music, videos, films, animes, TV shows, books, games, programs, drivers (a very few), OS images (Winblows :)). Go check it out!
p There you'll find music, videos, films, animes, TV shows, books, games, programs, drivers (a very few), OS images (Winblows mainly). Go check it out!
div
+isServiceUp("File upload", "dwelling-upload")
p
@ -136,7 +131,7 @@ block content
a(href='http://[300:a98d:d6d0:8a08::c]') ygg
p I've made a file upload service for ya with a limit of 128MiB per file, keeping it for 36 hours, and overall storage I dedicated for it is 100GiB.
div
+isServiceUp("Git", "gitea")
+isServiceUp("Git", "git")
p
a(href='https://git.arav.su') git.arav.su
| .
@ -149,7 +144,6 @@ block content
div
h3 Tor relay
p #[a(href='https://metrics.torproject.org/rs.html#details/CEF2FD0E1973EA04D1444DDAEFF1B0BC3C0C39B1' rel='nofollow noreferrer') metrics.torproject.org]
p It is set to use 8 MBits of my Internet connection. It cannot became a guard node because of dynamic IP-address.
p #[b Since 1st December 2021 Tor is blocked in Russia, so the relay is down.]
div
h3 I2P router
@ -159,50 +153,39 @@ block content
p.center That are available for a narrow circle of people.
div.columns
div
+isServiceUp("E-Mail server", "postfix")
p Postfix, Dovecot (w/Sieve), Spamassassin, ClamAV, OpenDMARC and OpenDKIM.
p Alas, I don't have a static IP. And there is not much sense in it because my ISP doesn't offer reverse DNS for regular clients (it'd be bloody awesome).
p It results in my messages ends up in a spam box at best. Well, Yandex, Google, Microsoft Live, and Rambler lets me in an Inbox. :) But if service use Spamhaus' blocklists then I'm being rejected.
p #[b TLDR; I may not be able to send a reply].
+isServiceUp("E-Mail server", "mail")
p Postfix, Dovecot (w/Sieve), rspamd, ClamAV.
div
+isServiceUp("XMPP/Jabber", "prosody")
p Prosody.
div
+isServiceUp("Mumble", "murmurd")
+isServiceUp("Mumble", "mumble")
p #[a(href="mumble://arav.su") mumble://arav.su]
p It's private, but you still can join an entrance room where you can only write messages. A certificate is necessary.
p Certificate is necessary. Only an entrance room is open for non-members.
div
+isServiceUp("TeamSpeak 3", "ts3server")
+isServiceUp("TeamSpeak 3", "teamspeak3")
p #[a(href="ts3server://arav.su") ts3server://arav.su]
p Same as with Mumble applies to TS. It's security level is set to 29, so is yours identifier's level should be at least that high.
div
h3 Game servers
p All game servers are private, if there's exception I'll mention it in its description. They are listed in a section below.
p Some servers are listed in an in-game server list and theirs names looks like &ldquo;Arav's dwelling / &lt;Game name&gt;&rdquo;.
p And, of course, I don't run them simultaneously and start them only when needed.
p Expect poor performance because the server is a low-end laptop.
p Same as for Mumble. Your identifier should have a security level greater or equal to 29.
section#servers-games
h2 Game servers
div.columns
div
+isServiceUp("Minecraft", "forge-1.16.5")
+isServiceUp("Minecraft", "game-minecraft")
p.highlighted arav.su:25565
p Version is 1.16.5 currently. I homebrew #[a(href=files_site+"/games/minecraft/") clients] for it, and make installers for Windows using NSIS. You'll need to set a PLAYER and MC_DIR variables in scripts. And change JVM_PARAMS to your preferences (-Xmx usually needs to be adjusted). But the installers will handle it for you.
p #[a(href='/minemap') Web map].
p Now run a version 1.20.4 with fabric. Here's a #[a(href='https://files.arav.su/file/games/minecraft/1.20.4-fabric-modpack.zip') modpack].
div
+isServiceUp("Starbound", "starbound_server")
+isServiceUp("Avorion", "game-avorion")
p Server is listed in a server list as &ldquo;Arav's dwelling / Avorion&rdquo;. Whitelist is enabled. Bring your SteamID64 if you want to play here.
div
+isServiceUp("Starbound", "game-starbound")
p.highlighted arav.su:21065
p Server is using a Frackin' Universe mod.
p Don't forget to set &ldquo;Allow assets mismatch&rdquo; option that can be found on the first page of the &ldquo;Options&rdquo; menu.
p Access is restricted using accounts. Contact me if you want to play here, you would need to give me a nickname and a password.
div
+isServiceUp("Avorion", "AvorionServer")
p Server is listed in a server list as &ldquo;Arav's dwelling / Avorion&rdquo;. Whitelist is enabled. Bring your SteamID64 if you want to play here.
div
+isServiceUp("Project Zomboid", "ProjectZomboid")
+isServiceUp("Project Zomboid", "game-pzomboid")
p.highlighted arav.su:16261
p Server is listed as &ldquo;Arav's dwelling / Project Zomboid&rdquo;. Whitelist is enabled.
div
+isServiceUp("Don't Starve Together", "dontstarve_dedicated_server_nullrenderer_x64")
+isServiceUp("Don't Starve Together", "game-dontstarve")
p.highlighted arav.su:10899
p Server is listed as &ldquo;Arav's dwelling / Don't Starve Together&rdquo;.
section#servers-inner-services
@ -211,46 +194,43 @@ block content
div.columns
div
h3 Web-server
p NGiNX #[s + PHP-FPM (just for phpMyAdmin)] #[s + NodeJS] + Go.
p NGiNX FTW.
div
h3 Database server
p #[s MariaDB managed with phpMyAdmin] Replaced by SQLite3 on my services.
h3 Database
p #[s MariaDB managed with phpMyAdmin] was replaced by SQLite3 on my services.
div
h3 VPN
p #[s OpenVPN] Wireguard.
div
h3 Network file share
p Samba.
p Samba and NFSv4.
div
h3 Torrent seedbox
h3 Torrents
p Transmission-cli gets shit done.
p The only annoying thing is that it sometimes creates .part files for one of unchecked files.
div
h3 Print server
h3 Printing
p CUPS with CCP (Canon CAPT printer).
p Holy shit, it finally works! #[s Wow, even after kernel update it doesn't require a reboot anymore!] Actually, requires. :)
p Holy shit, it finally works! #[s Wow, even after kernel update it doesn't require a reboot anymore!] #[s Actually, requires. :)] Sometimes do, sometimes not. xD
div
h3 DNS server
h3 DNS
p BIND9 via DNSCrypt-proxy.
p For LAN I use &ldquo;home.arpa&rdquo; special-use domain introduced by RFC 8375. And for uniqueness &ldquo;arav.home.arpa&rdquo; specifically.
p Now I serve my domain using a VPS as a slave.
section#contacts
h2 Contacts
span E-Mail:&nbsp;#[a(href="mailto:me@arav.su" title='May not be able to reply due to being blacklisted because of residental dynamic IP.') me@arav.su]
span Jabber:&nbsp;#[a(href="xmpp:arav@arav.su") arav@arav.su]
span E-Mail:&nbsp;#[a(href="mailto:me@arav.su") me@arav.su]
br
span
| PGP&nbsp;key:&nbsp;#[a(href="~arav/2E873A7831FF0BB640ACEDA5D22A817D95815393.asc") 2E87 3A78 31FF 0BB6 40AC EDA5 D22A 817D 9581 5393] (available through #[a(href="https://wiki.gnupg.org/WKD" rel="nofollow noreferrer") Web Key Directory])
br
span
| Jabber OMEMO fingerprint: 5F705E2C 9CE0F56D BD28F52D 6744FDD3 4477E9C7 CB856590 BDEF5EE1 2F6D566C
| PGP&nbsp;key:&nbsp;#[a(href="/~arav/739850CD5051DE554368709225969B23DCB5CA34.asc") 7398 50CD 5051 DE55 4368 7092 2596 9B23 DCB5 CA34] (available through #[a(href="https://wiki.gnupg.org/WKD" rel="nofollow noreferrer") Web Key Directory])
section#donation
h2 Donation
a(href="monero:48namnfX17TX1kEGCpkXaRWhtw8p92cQjd5uQg7ivybgUuW4BTVaX8egxQhEi75JwuUGn3MDLKHYGNhu4eCfM6dRAAL2QAq") monero:
| 48namnfX17TX1kEGCpkXaRWhtw8p92cQjd5uQg7ivybgUuW4BTVaX8egxQhEi75JwuUGn3MDLKHYGNhu4eCfM6dRAAL2QAq
br
| #[a(href="https://www.donationalerts.com/r/arav") DonationAlerts]
| #[a(href="https://qiwi.com/n/UPPON082") QIWI]
| #[a(href="https://www.tinkoff.ru/rm/andreev.aleksandr1164/cksD590894/") Tinkoff]
| #[a(href="https://www.tinkoff.ru/rm/andreev.aleksandr1164/5nVjK98501") Tinkoff]
| #[a(href="https://www.tinkoff.ru/baf/5zRsqEQic6r") Tinkoff рефералка]
section#banners
h2 Banners
p In case you found my site anyhow useful and would like to add me to your links page here are the banners for you.

View File

@ -5,7 +5,7 @@ block meta_description
block append head
link(href='/assets/css/articles.css' rel='stylesheet')
link(rel='canonical' href='#{host}/stuff/article/#{canonical}')
link(rel='canonical' href='/stuff/article/'+canonical)
block nav
a(href='/') Home
@ -22,5 +22,6 @@ block content
h2= title
div.menu
a(href='/stuff#articles') Go back to articles list
time(datetime=util.ToClientTimezone(date, r).Format("2006-01-02")) #{util.ToClientTimezone(date, r).Format("02 January 2006")}
- dctz := util.ToClientTimezone(date, r)
time(datetime=dctz.Format("2006-01-02")) #{dctz.Format("02 January 2006")}
| !{body}

View File

@ -9,7 +9,7 @@ html(lang='en')
meta(name='theme-color' content='#cd2682')
block meta_description
link(rel='icon' href='/assets/img/favicon.svg' sizes='any' type='image/svg+xml')
link(rel='alternate' href='rss.xml' type='application/rss+xml' title="Arav's dwelling")
link(rel='alternate' href='/rss.xml' type='application/rss+xml' title="Arav's dwelling")
link(href='/assets/css/main.css' rel='stylesheet')
body
header
@ -22,4 +22,4 @@ html(lang='en')
footer
a(href='/rss.xml' title="Stay up to date on what's going on.") RSS feed
br
| 2017&mdash;2023 Arav &lt;#[a(href='mailto:me@arav.su') me@arav.su]&gt; #[a(href='/privacy') Privacy statements]
| &copy; 2017&mdash;2024 Alexander &quot;Arav&quot; Andreev &lt;#[a(href='mailto:me@arav.su') me@arav.su]&gt; #[a(href='/privacy') Privacy statements]

View File

@ -4,14 +4,7 @@ block meta_description
meta(name='description' content=http.StatusText(code))
block append head
style(type="text/css").
#error {
font-size: 3.5rem;
line-height: 5rem;
text-align: center;
margin: 6rem 0; }
#error h1 { font-size: 8rem; }
link(href='/assets/css/error.css' rel='stylesheet')
block nav
a(href='/') Home
@ -22,11 +15,14 @@ block nav
h1 #{http.StatusText(code)}
block content
:go:func ErrorXXX(title, reason, message string, code int)
section#error
h1 #{code}
| #{http.StatusText(code)}
:go:func ErrorXXX(title, reason, message, referer string, code int)
section#error
h1 #{code}
| #{http.StatusText(code)}
if reason != ""
p #{reason}
if message != ""
p #{message}
if referer != ""
section
h2 #[a(href=referer) Go back]

View File

@ -31,6 +31,8 @@ block content
span.checkboxes
input(type='checkbox' id='hide-website' name='hide_website' checked='')
label(for='hide-website') Hide website #[small (only I can see if set)]
br
small Use &gt; to make a quote.
span.captcha
input(type='hidden' value=captcha_id name='captcha_id')
img(src='/api/captcha/'+captcha_id+'/image', alt="CAPTCHA" width='160' height='40')

View File

@ -1,7 +1,7 @@
extends base.pug
block meta_description
meta(name='description' content="A homepage of a russian guy Alexander aka Arav. Not just homepage, but file share, radio and upload services as well.")
meta(name='description' content="A homepage of a russian guy Alexander aka Arav. Not just homepage, but something more...")
block append head
link(href='assets/css/index.css' rel='stylesheet')
@ -20,7 +20,7 @@ block content
a(href='https://arav.su') arav.su
| .
a(href='http://moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion') onion
| .
| .
a(href='http://[300:a98d:d6d0:8a08::f]') ygg
| .
a(href='http://arav.i2p') i2p
@ -31,7 +31,7 @@ block content
a(href='https://radio.arav.su') radio
| .
a(href='http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion') onion
| .
| .
a(href='http://[300:a98d:d6d0:8a08::e]') ygg
| .
a(href='http://radio.arav.i2p') i2p
@ -40,7 +40,7 @@ block content
a(href='https://files.arav.su') files
| .
a(href='http://qf5e43nlhvnrutmikuvbdfj3cmtthokpbaxtkm6mjlslttzvtgm4fxid.onion') onion
| .
| .
a(href='http://[300:a98d:d6d0:8a08::d]') ygg
| .
a(href='http://files.arav.i2p') i2p
@ -49,7 +49,7 @@ block content
a(href='https://upload.arav.su') upload
| .
a(href='http://4usftbmjpfexkr2x5xbp5ukmygpmg4fgrnx2wbifsexqctooz5hmviyd.onion') onion
| .
| .
a(href='http://[300:a98d:d6d0:8a08::c]') ygg
| .
a(href='http://upload.arav.i2p') i2p
@ -58,10 +58,10 @@ block content
a(href='https://git.arav.su') git
| .
a(href='http://qqitm7qlsbbubwmjos4cqzmvkqidg34rfnbyhuydhalep33fbvh22xyd.onion') onion
| .
| .
a(href='http://[300:a98d:d6d0:8a08::b]') ygg
| .
a(href='http://git.arav.i2p') i2p
sup #[a(href="http://git.arav.i2p/?i2paddresshelper=eFIfcBUv3lHFSnglHfncs5XXtYwm9gCpmAYuio~9CeENBAXKRggPiY1tQC-otCon2hCSpr56WlVBeZk1txKuUnbjHTN7GBFaKW5wJEO2WmKEWPKdcjUDOYZN0D3TwXaYfiBuELD3200lBfDmPEJ01iC2o7B5yvpOqtEKDcaqkIp4vafDuPPumJ~XiCGdUAe~vr52w3Tbuz5x7wbltk-gUELY0-ZAQBos4jOJ6QT1W1lhycHPhAK8qslgwfk94opyIl2pkRyuJhU-2VHc6Fsd621VXC86YAMT1SIfTZlFpoGVCFXDM~BXaLvygFaKf62qardAe0T48Ax6GxosAKXe-yLCVRaiD3KErULfwZXl23kQzRfxM4odG4DWeXawtuvypOmTjHT1skQHU0h52ujye5nT~2bOy14HkCoCnxJ7gSj3MjkmWLd1JhBsPH4ymRmI7jFJR1GYl8Wp5IigMBBzWfJUEEjS7QDHaRo5TCZJ9SXz6sgkGdfh74~r8FWL559gBQAEAAcAAA==" title="address helper") ah]
section
p Welcome, Anon. I'm Arav, I self-host some services for myself, friends and you. Not much I have to offer, but maybe you'll find something useful for yourself. :)
p Welcome, Anon. I'm Alexander aka Arav, I self-host some services for myself, friends and you. Not much I have to offer, but maybe you'll find something useful for yourself. :)

View File

@ -17,7 +17,7 @@ block nav
block content
:go:func Mindflow(title string, posts []mindflow.Post, categories []mindflow.Category, r *http.Request)
p.center Here I post updates on websites and infrastructure, my very important opinions and thoughts no one asked for. If you'd like to subscribe to this bullshittery then #[a(href='rss.xml') RSS feed] at your service. :)
p.center Here I post updates on websites and infrastructure, my very important opinions and thoughts no one asked for. If you'd like to subscribe to this bullshittery then #[a(href='/rss.xml') RSS feed] at your service. :)
section#filter.hidden
p.center
@ -32,8 +32,15 @@ block content
a(href=`#${post.PostID()}`)
h3= post.Category.Name + ": " + post.Title
each line in strings.Split(post.Body, "\n")
p!= line
if (len(line) > 0 && line[0] == '>')
p.quote!= line
else
p!= line
footer
if (post.URL != "")
a(href=post.PostURL(r.Host, false)) #{post.PostURL(r.Host, false)}
else
span
time(datetime=util.ToClientTimezone(post.Date, r))= util.ToClientTimezone(post.Date, r).Format(time.RFC1123)
else
p.center Nothing? There must be some... Looks like database went down.

View File

@ -37,6 +37,7 @@ block content
each category in categories
option(value=category.ID) #{category.Name}
input(type='text', placeholder='Title' name='title' required='')
input(type='text', placeholder='URL' name='url')
textarea(placeholder='Body post' name='body' required='')
button(type="submit") Add
section
@ -55,6 +56,7 @@ block content
option(value=category.ID) #{category.Name}
input(type='hidden', name='post-id' value=post.ID)
input(type='text', placeholder='Title' name='title' value=post.Title required='')
input(type='text', placeholder='URL' name='url' value=post.URL)
textarea(placeholder='Body post' name='body' required='')!= post.Body
button(name='edit-post') Edit
button(name='delete-post') Delete

View File

@ -6,15 +6,15 @@ rss(version='2.0')
title Arav's dwelling
description Updates on my websites and infrastructure.
language en-gb
link= host
| <link>#{host}</link>
each post in posts
item
title= post.Title
category= post.Category.Name
guid!= `${post.PostID()}`
pubDate= util.ToClientTimezone(post.Date, r).Format("20060102-150405")
link!= `${host}/mindflow#${post.PostID()}`
pubDate= util.ToClientTimezone(post.Date, r).Format(time.RFC1123Z)
| <link>#{post.PostURL(r.Host, true)}</link>
author!= author
description
| <![CDATA[

View File

@ -18,8 +18,10 @@ block content
p.center Here lies everything I've made that I'm willing to share.
section#articles
h2 Articles
p These articles are more like the sysadmin's notes. I describe those parts here that I did myself. The date here represents when article was updated last time.
table
tr
th Last Update
th Article
each entry in metadata
tr
td
@ -28,19 +30,29 @@ block content
a(href=entry.URL) #{entry.Title}
section#programs-scripts
h2 Programs and scripts
p.center Simple, yet useful (at least for me) programs and scripts I made.
table
tr
td mccl
td 0.1.2 (14 December 2023)
td Go
td GPLv3
td
a(href=git_site+'/Arav/mccl') source
a(href=git_site+'/Arav/mccl/releases') releases
tr
td(colspan='5')
p A console Minecraft launcher. Take a look at README.md for explanation.
tr
td httpr
td 0.2.0 (27 May 2023)
td 0.3.2 (20 September 2023)
td Go
td MIT
td
td
a(href=git_site+'/Arav/httpr') source
a(href=git_site+'/Arav/httpr/releases') releases
tr
td(colspan='5')
p A simple HTTP router that supports having both regular and parametrised path's parts at the same level, like #[code /assets/*filepath] and #[code /:a/:b] in the same HTTP method.
p A simple HTTP router that supports having both regular and parametrised path's parts at the same level, like #[code /assets/*filepath] and #[code /:a/:b] with the same HTTP method.
p Yeah, not as efficient as httprouter is, but in my case no performance loose was noticed (on a small amount of paths). Yet I gained prettiness because it allowed me, for example, to ditch #[code /f/] part and leave just #[code /:hash/:name] instead of #[code /f/:hash/:name] in a dwelling-upload service.
tr
td justguestbook
@ -48,23 +60,23 @@ block content
td Go
td MIT
td
a(href=git_site+'/Arav/justcaptcha') source
a(href=git_site+'/Arav/justguestbook') source
tr
td(colspan='5')
p A simple guestbook with owner's replies implementation made into a library.
tr
td justcaptcha
td 2.0.2 (6 May 2023)
td 2.1.0 (12 August 2023)
td Go
td MIT
td
a(href=git_site+'/Arav/justcaptcha') source
tr
td(colspan='5')
p A simple CAPTCHA implementation that can work as a standalone service or as a library.
p A simple CAPTCHA implementation.
tr
td kwh-cost
td 1.0.0 (24 December 2021)
td 1.1.1 (23 September 2023)
td C
td MIT+NIGGER
td
@ -74,7 +86,7 @@ block content
p KWh cost calculator in C.
tr
td httpprocprobed
td 2.0.1 (4 February 2023)
td 3.1.0 (16 December 2023)
td Go
td MIT+NIGGER
td
@ -115,7 +127,7 @@ block content
a(href=git_site+'/Arav/PiggyBank/releases') releases
tr
td(colspan='5')
p A program to help you to keep track of your piggy bank.
p A program to help you to keep track of your piggy bank. A simple script I once wrote that I rewrote and made into a package just to learn how to do it.
section#music
h2 Music
p There was a period in my life when I was playing with audio sequencers. I lost all project files and only 3 tracks survived in mp3 that #[a(href=files_site+"/music/My%20tracks,%20that%20survived/") you can get here].

View File

@ -6,8 +6,6 @@ import (
"net/http"
)
// To install a Jade compiler: go install github.com/Joker/jade/cmd/jade@latest
//
//go:generate $GOPATH/bin/jade -basedir ./templates -pkg=web -writer index.pug stuff.pug mindflow.pug
//go:generate $GOPATH/bin/jade -basedir ./templates -pkg=web -writer about.pug guestbook.pug rss.pug
//go:generate $GOPATH/bin/jade -basedir ./templates -pkg=web -writer guestbook_admin.pug mindflow_admin.pug