commit 965aae7f5717bbada2bffb4e07758cc098efbd5f Author: 諏訪子 Date: Wed Jan 21 03:36:58 2026 +0900 SVNからのミラー diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8348e5c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,45 @@ +# 2.3.0 +* GPL→ISC +* GNU Make→BSD Make +* ヘルプとバージョン表示(CLI)の削除 + +# 2.2.0 +* ポート番号の修正 +* 言語はliblocale化 +* 複数言語対応 + +# 2.1.1 +* バグを修正 + +# 2.1.0 +* ローカライズは関数化 +* API機能性 +* サーバーのソースコードを短くに + +# 2.0.2 +* Makefileでの「make install」部分を修正 +* manページで「オプションなし」部分を追加 +* 「短熟」→「短縮」を修正 +* クッキーは無効にする又はクッキーが未対応のブラウザ対応の修正 + +# 2.0.1 +* 送信ページの無英訳を修正 +* URLは500文字移行のエラー未表示を修正 +* ページデータの値を改良 +* ページでバージョンの表示を追加 + +# 2.0.0 +* Makefile化 +* ソースコードは複数ファイルに分ける +* コマンドラインからURL短縮 +* バージョンの表示 +* ヘルプの表示 +* manページ +* ポート番号はご自由に決める様にした(デフォルトは9910) + +# 1.0.0 +* PHPからGoに交換しました +* 今度からバージョンを付きます + +# それ以前 +* 色々 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..777a97f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright © 2018-2024 by 076.moe + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD +TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62ec25d --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +UNAME_S != uname -s + +NAME != cat main.go | grep "var sofname" | awk '{print $$4}' | sed "s/\"//g" +VERSION != cat main.go | grep "var version" | awk '{print $$4}' | sed "s/\"//g" + +PREFIX = /usr/local +.if ${UNAME_S} == "Linux" +PREFIX = /usr +.endif + +MANPREFIX = ${PREFIX}/share/man +.if ${UNAME_S} == "OpenBSD" +MANPREFIX = ${PREFIX}/man +.endif + +CNFPREFIX=/etc +.if ${UNAME_S} == "FreeBSD" || ${UNAME_S} == "NetBSD" || ${UNAME_S} == "Dragonfly" +CNFPREFIX=${PREFIX}/etc +.endif + +CC=CGO_ENABLED=0 go build +RELEASE=-ldflags="-s -w" -buildvcs=false + +all: + ${CC} ${RELEASE} -o ${NAME} + +release: + mkdir -p release/bin + env GOOS=linux GOARCH=amd64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-linux-amd64 + env GOOS=linux GOARCH=arm64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-linux-arm64 + env GOOS=linux GOARCH=riscv64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-linux-riscv64 + env GOOS=linux GOARCH=ppc64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-linux-ppc64 + env GOOS=linux GOARCH=mips64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-linux-mips64 + env GOOS=openbsd GOARCH=amd64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-openbsd-amd64 + env GOOS=openbsd GOARCH=arm64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-openbsd-arm64 + env GOOS=openbsd GOARCH=mips64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-openbsd-mips64 + env GOOS=openbsd GOARCH=ppc64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-openbsd-ppc64 + env GOOS=openbsd GOARCH=riscv64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-openbsd-riscv64 + env GOOS=openbsd GOARCH=sparc64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-openbsd-sparc64 + env GOOS=freebsd GOARCH=amd64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-freebsd-amd64 + env GOOS=freebsd GOARCH=arm64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-freebsd-arm64 + env GOOS=freebsd GOARCH=riscv64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-freebsd-riscv64 + env GOOS=netbsd GOARCH=amd64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-netbsd-amd64 + env GOOS=netbsd GOARCH=arm64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-netbsd-arm64 + env GOOS=illumos GOARCH=amd64 ${CC} ${RELEASE} -o \ + release/bin/${NAME}-${VERSION}-illumos-amd64 + +clean: + rm -f ${NAME} ${NAME}-${VERSION}.tar.gz + +dist: clean + mkdir -p ${NAME}-${VERSION} release/src + cp -R LICENSE.txt Makefile README.md CHANGELOG.md\ + view static logo.jpg\ + ${NAME}.1 *.go *.json go.mod go.sum ${NAME}-${VERSION} + tar zcfv release/src/${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION} + rm -rf ${NAME}-${VERSION} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < ${NAME}.1 > ${DESTDIR}${MANPREFIX}/man1/${NAME}.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/${NAME}.1 + mkdir -p ${DESTDIR}${CNFPREFIX}/${NAME} + chmod 755 ${DESTDIR}${CNFPREFIX}/${NAME} + +uninstall: + rm -f ${DESTDIOR}${PREFIX}/bin/${NAME}\ + ${DESTDIR}${MANPREFIX}/man1/${NAME}.1\ + ${DESTDIR}${CNFPREFIX}/${NAME} + +.PHONY: all release clean dist install uninstall diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b18bfe --- /dev/null +++ b/README.md @@ -0,0 +1,282 @@ +# URLロリ +クッソ小さいURL短縮作成ソフトだわ〜♡ + +## インストールする方法 + +### 従属ソフト + +* Go 1.19以上 +* nginx又はOpenBSDのrelayd +* 良いOS (GNU/Linux、OpenBSD、又はFreeBSD) + +## インストールする方法 + +### 全部(opendoasを使わなければ、sudoをご利用、又はopendoasをインストールして下さい) + +```sh +make +doas make install +``` + +### OpenBSD + +```sh +nvim /etc/rc.d/urloli +``` + +``` +#!/bin/ksh + +daemon="/usr/local/bin/urloli -s" + +. /etc/rc.d/rc.subr + +rc_bg=YES +rc_reload=NO + +rc_cmd $1 +``` + +```sh +chmod +x /etc/rc.d/urloli +rcctl enable urloli +rcctl start urloli +``` + +### FreeBSD + +```sh +nvim /usr/local/etc/rc.d/urloli +``` + +``` +#!/bin/sh + +# PROVIDE: urloli +# REQUIRE: NETWORKING SYSLOG +# KEYWORD: shutdown +# +# Add the following lines to /etc/rc.conf to enable urloli: +# +#urloli_enable="YES" + +. /etc/rc.subr + +name="urloli" +rcvar="urloli_enable" + +load_rc_config $name + +: ${urloli_enable:="NO"} +: ${urloli_facility:="daemon"} +: ${urloli_priority:="debug"} + +command="/usr/local/bin/${name}" +procname="/usr/local/bin/${name}" + +pidfile="/var/run/${name}.pid" + +start_cmd="${name}_start" + +urloli_start() { + for d in /var/db/urloli /var/log/urloli; do + if [ ! -e "$d" ]; then + mkdir "$d" + fi + done + /usr/sbin/daemon -S -l ${urloli_facility} -s ${urloli_priority} -T ${name} \ + -p ${pidfile} \ + /usr/bin/env -i \ + "PATH=/usr/local/bin:${PATH}" \ + $command +} + +run_rc_command "$1" +``` + +```sh +sysrc urloli_enable=YES +service start urloli +``` + +### Crux + +```sh +nvim /etc/rc.d/urloli +``` + +``` +#!/bin/sh +# +# /etc/rc.d/urloli: start/stop the urloli daemon +# + +SSD=/sbin/start-stop-daemon +NAME=urloli +PROG=/usr/bin/$NAME +PIOD=/run/$NAME.pid + +case $1 in +start) + $SSD --start --pidfile $PID --exec $PROG + ;; +stop) + $SSD --stop --retry 10 --pidfile $PID + ;; +restart) + $0 stop + $0 start + ;; +status) + $SSD --status --pidfile $PID + case $? in + 0) echo "$PROG は実行中。pid $(cat $PID)" ;; + 1) echo "$PROG は実行していませんが、pidファイルは「 $PID 」として存在しそう" ;; + 3) echo "$PROG は停止中" ;; + 4) echo "状況不明" ;; + esac + ;; +*) + echo "usage: $0 [start|sto@|restart|status]" + ;; +esac + +# End of file +``` + +### Devuan/Debian/Ubuntu/Arch/Artix/AlmaLinux等 + +```sh +nvim /etc/init.d/urloli +``` + +``` +#!/bin/sh +# +# chkconfig: 35 90 12 +# description: URL Loli server +# + +NAME=urloli +DESC=urloli +DAEMON=/usr/bin/$NAME + +start () { + echo "URLロリサーバーは開始中:\n" + /usr/bin/urloli -s 9910 &>/dev/null & + touch /var/lock/subsys/urloli + echo +} + +stop () { + echo "URLロリサーバーは終了中:\n" + pkill urloli + rm -f /var/lock/subsys/urloli + echo +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + restart|reload|condrestart) + stop + start + ;; + *) + echo $"Usage: $0 {start|stop|restart|status}" + exit 1 +esac +``` + +## ウェブサーバー + +### OpenBSD + +```sh +nvim /etc/relayd.conf +``` + +``` +# $OpenBSD: relayd.conf,v 1.5 2018/05/06 20:56:55 benno Exp $ +# +relayd_address="0.0.0.0" + +table { 127.0.0.1 } + +http protocol reverse_proxy { + tls keypair "DOMAIN" + match request header append "X-Forwarded-For" value "$REMOTE_ADDR" + match request header append "X-Forwarded-Port" value "$REMOTE_PORT" + + match response header set "Referrer-Policy" value "same-origin" + match response header set "X-Frame-Options" value "deny" + match response header set "X-XSS-Protection" value "1; mode=block" + match response header set "X-Content-Type-Options" value "nosniff" + match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains; preload" + match response header set "Cache-Control" value "max-age=86400" + + pass request quick header "Host" value "urlo.li" forward to + + return error + pass +} + +relay www { + listen on $relayd_address port 443 tls + protocol $relayd_address + + forward to check tcp port 9910 +} +``` + +### その他 + +```sh +server { + server_name DOMAIN www.DOMAIN; + root /var/www/htdocs/urloli; + + access_log off; + error_log off; + + if ($host = www.DOMAIN) { + return 301 https://DOMAIN$request_uri; + } + + location /static { + try_files $uri $uri/ /static/$args; + } + + location / { + proxy_pass http://localhost:9910; + } + + listen [::]:443 ssl ipv6only=on; + listen 443 ssl; + ssl_certificate /etc/letsencrypt/live/DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/DOMAIN/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf +} + +server { + if ($host = DOMAIN) { + return 301 https://DOMAIN$request_uri; + } + + if ($host = www.DOMAIN) { + return 301 https://DOMAIN$request_uri; + } + + listen 80; + listen [::]:80; + server_name DOMAIN www.DOMAIN; + return 404; +} +``` diff --git a/checkers.go b/checkers.go new file mode 100644 index 0000000..d5859f8 --- /dev/null +++ b/checkers.go @@ -0,0 +1,16 @@ +package main + +import ( + "strings" + "unicode/utf8" +) + +// http://かhttps://で始まるかどうか +func checkprefix (url string) bool { + return strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") +} + +// URLは500文字以内かどうか +func checkcharlim (url string) bool { + return utf8.RuneCountInString(url) <= 500 +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..31a361b --- /dev/null +++ b/config.go @@ -0,0 +1,97 @@ +package main + +import ( + "fmt" + "encoding/json" + "io/ioutil" + "runtime" + "os" + "errors" +) + +type Config struct { + configpath, linkpath, webpath, domain, ip string +} + +func geturl (url string, linkpath string, checkjson bool) (string, string) { + payload := getlinks(linkpath) + + for k := range payload { + if checkjson { + if url == payload[k] { + return url, k + } + } else { + if url == k { + return payload[k].(string), k + } + } + } + + return "", "" +} + +func getlinks (linkpath string) map[string]interface{} { + data, err := ioutil.ReadFile(linkpath) + if err != nil { + fmt.Println("links.jsonを開けられません: ", err) + } + + var payload map[string]interface{} + json.Unmarshal(data, &payload) + + return payload +} + +func getconf () (Config, error) { + var cnf Config + + prefix := "/usr" + if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" { + prefix += "/local" + } else if runtime.GOOS == "netbsd" { + prefix += "/pkg" + } + + cnf.configpath = "/etc/urloli/config.json" + cnf.linkpath = "/etc/urloli/links.json" + if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" { + cnf.configpath = prefix + cnf.configpath + cnf.linkpath = prefix + cnf.linkpath + } + + data, err := ioutil.ReadFile(cnf.configpath) + if err != nil { + fmt.Println("config.jsonを開けられません: ", err) + return cnf, errors.New( + "コンフィグファイルは " + cnf.configpath + " に創作して下さい。", + ) + } + + var payload map[string]interface{} + json.Unmarshal(data, &payload) + if payload["webpath"] == nil { + return cnf, errors.New("「webpath」の値が設置していません。") + } + if payload["domain"] == nil { + return cnf, errors.New("「domain」の値が設置していません。") + } + if payload["ip"] == nil { + return cnf, errors.New("「ip」の値が設置していません。") + } + if _, err := os.Stat(payload["webpath"].(string)); err != nil { + fmt.Printf("%v\n", err) + return cnf, errors.New("mkdirコマンドを使って、 " + payload["webpath"].(string)) + } + if !checkprefix(payload["domain"].(string)) { + return cnf, errors.New( + "URLは「http://」又は「https://」で始める様にして下さい。", + ) + } + cnf.webpath = payload["webpath"].(string) + cnf.domain = payload["domain"].(string) + cnf.ip = payload["ip"].(string) + payload = nil + + return cnf, nil +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..10bccc0 --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "domain": "https://urlo.li", + "webpath": "/var/www/htdocs/urloli", + "ip": "0.0.0.0" +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c2d99c3 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module 076/urloli + +go 1.18 + +require gitler.moe/suwako/goliblocale v1.0.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7642e2e --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +gitler.moe/suwako/goliblocale v1.0.0 h1:QiQKNzdgpavwmAaYhAb5pth0I6qS8IJ7q2hYAgpXacU= +gitler.moe/suwako/goliblocale v1.0.0/go.mod h1:pdv9Go5taevY8ClBOA+oLXjGap7G1RmIVKUMF8HSJmU= diff --git a/links.sample.json b/links.sample.json new file mode 100644 index 0000000..4e4b20b --- /dev/null +++ b/links.sample.json @@ -0,0 +1,4 @@ +{ + "nuqvx": "https://technicalsuwako.moe", + "076": "https://076.moe" +} diff --git a/locale/en.json b/locale/en.json new file mode 100644 index 0000000..032c4d1 --- /dev/null +++ b/locale/en.json @@ -0,0 +1,16 @@ +{ + "top": "Top", + "logo": "Logo", + "fuseiurl": "Invalid URL", + "tansyukuzumi": "Shortened", + "mikensyutu": "Not found", + "errfusei": "The URL should start with \"http://\" or \"https://\".", + "errcharlim": "The URL should be less than 500 characters.", + "errurlent": "Please enter a URL.", + "errurlnai": "This URL could not be found.", + "totop": "Return to toppage", + "canunderaccess": "Please enter a URL.", + "enterurl": "Please enter a URL.", + "submit": "Submit", + "langchange": "Change language" +} diff --git a/locale/ja.json b/locale/ja.json new file mode 100644 index 0000000..59a529f --- /dev/null +++ b/locale/ja.json @@ -0,0 +1,16 @@ +{ + "top": "トップ", + "logo": "ロゴ", + "fuseiurl": "不正なURL", + "tansyukuzumi": "短縮済み", + "mikensyutu": "未検出", + "errfusei": "URLは「http://」又は「https://」で始めます。", + "errcharlim": "URLは500文字以内です。", + "errurlent": "URLをご入力下さい。", + "errurlnai": "このURLを見つけられませんでした。", + "totop": "トップページに戻る", + "canunderaccess": "下記のURLからアクセス出来ます。", + "enterurl": "URLをご入力下さい", + "submit": "送信", + "langchange": "言語変更" +} diff --git a/logo.jpg b/logo.jpg new file mode 100644 index 0000000..8a83ef2 Binary files /dev/null and b/logo.jpg differ diff --git a/main.go b/main.go new file mode 100644 index 0000000..8fc60bc --- /dev/null +++ b/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "os" + "strconv" +) + +var sofname = "urloli" +var version = "2.3.0" + +func usage() { + fmt.Printf("%s-%s\nusage: %s [-s port] [url]\n", sofname, version, sofname) +} + +func main() { + cnf, err := getconf() + if err != nil { + fmt.Println(err) + return + } + args := os.Args + + if len(args) < 2 { + usage() + return + } + + if len(args) == 2 && args[1] == "-s" { + serv(cnf, 9910) + } else if len(args) == 2 && args[1] != "-s" { + if !checkprefix(args[1]) { + fmt.Println("URLは不正です。終了…") + return + } + + _, key := geturl(args[1], cnf.linkpath, true) + if (key != "") { + fmt.Println(cnf.domain + "/" + key) + } else { + fmt.Println(cnf.domain + "/" + insertjson(args[1], cnf.linkpath)) + } + return + } else if len(args) == 3 && args[1] == "-s" { + port, err := strconv.Atoi(args[2]) + if err != nil { + fmt.Printf("%qは数字ではありません。\n", args[2]) + return + } + + serv(cnf, port) + } +} diff --git a/makers.go b/makers.go new file mode 100644 index 0000000..54c1759 --- /dev/null +++ b/makers.go @@ -0,0 +1,39 @@ +package main + +import ( + "crypto/rand" + "encoding/json" + "io/ioutil" + "os" +) + +func mkstring () string { + stringchars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + newstring := "" + b := make([]byte, 5) + + // 乱数を生成 + if _, err := rand.Read(b); err != nil { + return "不明なエラー" + } + + // ランダムに取り出して文字列を生成 + for _, v := range b { + // index が stringchars の長さに収まるように調整 + newstring += string(stringchars[int(v)%len(stringchars)]) + } + + return newstring +} + +func insertjson (url string, linkpath string) string { + payload := getlinks(linkpath) + + newstring := mkstring() + payload[newstring] = url + m, _ := json.Marshal(&payload) + payload = nil + ioutil.WriteFile(linkpath, m, os.ModePerm) + + return newstring +} diff --git a/srv.go b/srv.go new file mode 100644 index 0000000..b9811a7 --- /dev/null +++ b/srv.go @@ -0,0 +1,236 @@ +package main + +import ( + "text/template" + "fmt" + "net/http" + "encoding/json" + "strings" + "log" + "os" + "path/filepath" + "gitler.moe/suwako/goliblocale" +) + +type ( + Page struct { + Tit, Err, Url, Dom, Lan, Ver, Ves string + i18n map[string]string + } + Api struct { + Cod int `json:"code"` + Err string `json:"error"` + Url string `json:"url"` + Mot string `json:"origin"` + New bool `json:"isnew"` + } + Stat struct { + Url string `json:"url"` + Ver string `json:"version"` + } +) + +func (p Page) T(key string) string { + return p.i18n[key] +} + +func initloc(r *http.Request) string { + supportLang := map[string]bool{ + "ja": true, + "en": true, + } + + cookie, err := r.Cookie("lang") + if err != nil { + return "ja" + } + + if _, ok := supportLang[cookie.Value]; ok { + return cookie.Value + } else { + return "ja" + } +} + +func serv(cnf Config, port int) { + dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + log.Fatal(err) + } + err = os.Chdir(dir) + if err != nil { + log.Fatal(err) + } + + http.Handle( + "/static/", + http.StripPrefix("/static/", http.FileServer(http.Dir(cnf.webpath + "/static"))), + ) + + ftmpl := []string{ + cnf.webpath + "/view/index.html", + cnf.webpath + "/view/header.html", + cnf.webpath + "/view/footer.html", + } + + http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(200) + buf, _ := json.MarshalIndent(&Stat{Url: cnf.domain, Ver: version}, "", " ") + _, _ = w.Write(buf) + }) + + http.HandleFunc("/api/lolify", func(w http.ResponseWriter, r *http.Request) { + lang := initloc(r) + i18n, err := goliblocale.GetLocale(cnf.webpath + "/locale/" + lang) + if err != nil { + fmt.Printf("liblocaleエラー:%v", err) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(200) + res := &Api{Cod: 500, Err: "未対応"} + if r.Method == "POST" { + err := r.ParseForm() + if err != nil { + fmt.Println(err) + res.Err = "失敗" + return + } + + if r.PostForm.Get("url") != "" { + addurl := r.PostForm.Get("url") + chkprx := checkprefix(addurl) + chklim := checkcharlim(addurl) + if !chkprx { + res = &Api{Cod: 400, Err: i18n["errfusei"]} + buf, _ := json.MarshalIndent(res, "", " ") + _, _ = w.Write(buf) + return + } + if !chklim { + res = &Api{Cod: 400, Err: i18n["errcharlim"]} + buf, _ := json.MarshalIndent(res, "", " ") + _, _ = w.Write(buf) + return + } + + if !chklim || !chkprx { + res = &Api{Cod: 400, Err: i18n["errurlent"]} + buf, _ := json.MarshalIndent(res, "", " ") + _, _ = w.Write(buf) + return + } + + chkfn, key := geturl(addurl, cnf.linkpath, true) + if chkfn != "" { + res = &Api{ + Cod: 200, + Url: cnf.domain + "/" + key, + Mot: addurl, + New: false, + } + } else { + res = &Api{ + Cod: 200, + Url: cnf.domain + "/" + insertjson(addurl, cnf.linkpath), + Mot: addurl, + New: true, + } + } + } + } + + buf, _ := json.MarshalIndent(res, "", " ") + _, _ = w.Write(buf) + }) + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + data := &Page{Ver: version, Ves: strings.ReplaceAll(version, ".", "")} + uri := r.URL.Path + lang := initloc(r) + + i18n, err := goliblocale.GetLocale(cnf.webpath + "/locale/" + lang) + if err != nil { + fmt.Printf("liblocaleエラー:%v", err) + return + } + data.i18n = i18n + data.Lan = lang + + // デフォルトページ=未検出 + data.Tit = i18n["mikensyutu"] + data.Err = i18n["errurlnai"] + ftmpl[0] = cnf.webpath + "/view/404.html" + tmpl := template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2])) + + if r.Method == "POST" { + err := r.ParseForm() + if err != nil { fmt.Println(err) } + if r.PostForm.Get("sosin") != "" { + if r.PostForm.Get("newadd") == "" { + data.Err = i18n["errurlent"] + return + } + + addurl := r.PostForm.Get("newadd") + chkprx := checkprefix(addurl) + chklim := checkcharlim(addurl) + + if !chkprx { + data.Tit = i18n["fuseiurl"] + data.Err = i18n["errfusei"] + return + } + + if !chklim { + data.Tit = i18n["fuseiurl"] + data.Err = i18n["errcharlim"] + return + } + + chkfn, _ := geturl(addurl, cnf.linkpath, true) + if chkfn != "" { + http.Redirect(w, r, addurl, http.StatusSeeOther) + return + } + + data.Url = insertjson(addurl, cnf.linkpath) + data.Dom = cnf.domain + data.Tit = i18n["tansyukuzumi"] + ftmpl[0] = cnf.webpath + "/view/submitted.html" + } else if r.PostForm.Get("langchange") != "" { + lang := r.PostForm.Get("lang") + http.SetCookie( + w, + &http.Cookie{Name: "lang", Value: lang, MaxAge: 31536000, Path: "/"}, + ) + http.Redirect(w, r, "/", http.StatusSeeOther) + return + } + } else { // r.Method == "GET" + if uri == "/" { + data.Tit = i18n["top"] + ftmpl[0] = cnf.webpath + "/view/index.html" + } else { + red, _ := geturl(uri[1:], cnf.linkpath, false) + if red != "" { + http.Redirect(w, r, red, http.StatusSeeOther) + return + } + } + } // r.Method + + tmpl = template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2])) + tmpl.Execute(w, data) + data = nil + }) + + fmt.Println(fmt.Sprint( + "http://" + cnf.ip + ":", + port, + " でサーバーを実行中。終了するには、CTRL+Cを押して下さい。", + )) + http.ListenAndServe(fmt.Sprint(cnf.ip + ":", port), nil) +} diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..6d42d2d Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/git.png b/static/git.png new file mode 100644 index 0000000..df3afde Binary files /dev/null and b/static/git.png differ diff --git a/static/logo.jpg b/static/logo.jpg new file mode 100644 index 0000000..9b9eaac Binary files /dev/null and b/static/logo.jpg differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..559a349 --- /dev/null +++ b/static/style.css @@ -0,0 +1,80 @@ +body { + background-color: #232629; + color: #fcfcfc; +} + +a { + color: #ea81e8; + text-decoration: none; +} + +hr { + border-color: #dd00dd; + box-shadow: 2px 2px 10px #ff00ff; + width: 100%; +} + +.headerimg { + border: 1px solid #f2f; + box-shadow: 0px 0px 11px 5px #f0f; +} + +.body { + margin: 0 auto; + max-width: 800px; + background-color: #21082b; + padding: 8px; + box-shadow: 0px 0px 11px 5px #f0f; +} + +.form { + margin: auto; + text-align: center; +} + +input[type="text"], input[type="submit"] { + border: 1px #f9f groove; + margin: 4px auto; +} + +input[type="text"] { + width: 99%; + max-width: 700px; + border-color: #d6a9d6; +} + +input { + background-color: #683c7a; + font-size: 24px; + border-radius: 4px; +} + +.body, input { + color: #d6a9d6; + border: 1px #ff3b3b groove; +} + +select { + background-color: #683c7a; + color: #d6a9d6; + font-size: 18px; + border-radius: 4px; + max-width: 700px; + border: 1px #f9f groove; + padding: 8px; + width: 200px; +} + +select, input.langchange { + height: 35px; + vertical-align: middle; +} + +.submit, .footer, h1 { + text-align: center; + margin-top: 32px; +} + +input.langchange { + font-size: 24px; +} diff --git a/urloli.1 b/urloli.1 new file mode 100644 index 0000000..6ca175b --- /dev/null +++ b/urloli.1 @@ -0,0 +1,29 @@ +.TH URLロリ 1 urloli\-VERSION +.SH ソフト名 +URLロリ - クッソ小さいURL短縮作成ソフトだわ〜♡ +.SH 概要 +.B urloli +[\fI\,オプション\/\fR] [\fI\,ポート番号\/\fR] +.SH 説明 +.PP +URLロリはクッソ小さいURL短縮作成ソフトです。 +.TP +.TP +\fB\-s [ポート番号]\fR +ポート番号でサーバーを開始(デフォルト=9910) +.TP +.TP +.B オプションなし +ローカルにURLを短縮 +.SH 会話 +.PP +XMPP: xmpp:moriyajinja@chat.xmpp.076.ne.jp?join +.br +IRC: irc.076.moe/6697 #moriyajinja +.br +メーリングリスト: (開発中) +.SH バグ報告 +.PP +バグは下記のURLまでご報告下さい: +.br +https://gitler.moe/suwako/urloli/issues diff --git a/view/404.html b/view/404.html new file mode 100644 index 0000000..5ff36fc --- /dev/null +++ b/view/404.html @@ -0,0 +1,4 @@ +{{template "header" .}} + {{ .Err }}
+ {{.T "totop"}} +{{template "footer" .}} diff --git a/view/footer.html b/view/footer.html new file mode 100644 index 0000000..e0aef3b --- /dev/null +++ b/view/footer.html @@ -0,0 +1,14 @@ +{{define "footer"}} + + + + +{{end}} diff --git a/view/header.html b/view/header.html new file mode 100644 index 0000000..38f55d2 --- /dev/null +++ b/view/header.html @@ -0,0 +1,22 @@ +{{define "header"}} + + + + + + + + URLロリ〜{{.Tit}} + + + + +

+ {{.T +

+
+

+ {{.T "top"}} +

+{{end}} diff --git a/view/index.html b/view/index.html new file mode 100644 index 0000000..99a9586 --- /dev/null +++ b/view/index.html @@ -0,0 +1,26 @@ +{{template "header" .}} +
+
+ + +
+
+
+ {{.T "enterurl"}} +
+
+ +
+ +
+
+
+{{template "footer" .}} diff --git a/view/submitted.html b/view/submitted.html new file mode 100644 index 0000000..41c1cc2 --- /dev/null +++ b/view/submitted.html @@ -0,0 +1,7 @@ +{{template "header" .}} + {{.T "canunderaccess"}} +
+ {{ .Dom }}/{{ .Url }} +

+ {{.T "totop"}} +{{template "footer" .}}