Compare commits

..

No commits in common. "da518345d5b60e96cca1fed52aed272ff3c9bfca" and "f2616c041b80facb159432d2c8c7e0f004676d55" have entirely different histories.

15 changed files with 17 additions and 166 deletions

View file

@ -1,26 +0,0 @@
on:
push:
branches:
- main
jobs:
docker:
runs-on: ubuntu-22.04
steps:
# - run: "echo reg: ${{ env.GITHUB_SERVER_URL }}, act: ${{ github.actor }}, sec: ${{ github.token }}"
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ${{ env.GITHUB_SERVER_URL }}
username: ${{ github.actor }}
password: ${{ secrets.REG_TOKEN }}
# -
# name: Set up QEMU
# uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: git.mstar.dev/${{ env.GITHUB_REPOSITORY }}:latest

View file

@ -17,7 +17,6 @@
and given appropriate descriptive information and given appropriate descriptive information
_or_ return an error defined (as public variable) in that package. _or_ return an error defined (as public variable) in that package.
Example: `other.Error("auth", "failed to do something important", originalError)` Example: `other.Error("auth", "failed to do something important", originalError)`
- Returned http errors must use `git.mstar.dev/mstar/goutils/webutils.ProblemDetails(StatusOnly)`.
## JS/TS ## JS/TS

View file

@ -1,24 +1,10 @@
FROM docker.io/node:22 AS build-ember FROM docker.io/node:22 AS build-ember
# TODO: Implement ember frontend build # TODO: Implement ember frontend build
COPY . /app
WORKDIR /app/frontend-reactive
RUN npm install && npm run build
FROM docker.io/golang:1.23 AS build-go FROM docker.io/golang:1.23 AS build-go
# TODO: Implement golang build # TODO: Implement golang build
FROM gcr.io/distroless/static-debian12:latest as release
COPY --from=build-ember /app /app
WORKDIR /app
RUN CGO_ENABLED=0 go build -o /app/linstrom .
# FROM fedora:latest AS release
FROM alpine:3 AS release
# TODO: Implement final release container # TODO: Implement final release container
COPY --from=build-go /app/linstrom /linstrom
ENTRYPOINT ["/linstrom"]
# OCI labels, following https://github.com/opencontainers/image-spec/blob/main/annotations.md # OCI labels, following https://github.com/opencontainers/image-spec/blob/main/annotations.md
# Make this one dynamic # Make this one dynamic

2
go.mod
View file

@ -5,7 +5,7 @@ go 1.23.0
toolchain go1.23.7 toolchain go1.23.7
require ( require (
git.mstar.dev/mstar/goutils v1.12.3 git.mstar.dev/mstar/goutils v1.12.1
github.com/BurntSushi/toml v1.4.0 github.com/BurntSushi/toml v1.4.0
github.com/dgraph-io/ristretto v0.2.0 github.com/dgraph-io/ristretto v0.2.0
github.com/eko/gocache/lib/v4 v4.1.6 github.com/eko/gocache/lib/v4 v4.1.6

4
go.sum
View file

@ -61,10 +61,6 @@ git.mstar.dev/mstar/goutils v1.12.0 h1:d88hLS8KnLUCI+8aWBR6228M43hxHdJpj8WuSqm4L
git.mstar.dev/mstar/goutils v1.12.0/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA= git.mstar.dev/mstar/goutils v1.12.0/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
git.mstar.dev/mstar/goutils v1.12.1 h1:HZKKzMNfx7JKSUi5s8SwwUFEqEX6xvkM6NMf+Pht+lo= git.mstar.dev/mstar/goutils v1.12.1 h1:HZKKzMNfx7JKSUi5s8SwwUFEqEX6xvkM6NMf+Pht+lo=
git.mstar.dev/mstar/goutils v1.12.1/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA= git.mstar.dev/mstar/goutils v1.12.1/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
git.mstar.dev/mstar/goutils v1.12.2 h1:twCnsl+WRgP52mV5D5FRVJK6Yst1/3VtulHd77U++BY=
git.mstar.dev/mstar/goutils v1.12.2/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
git.mstar.dev/mstar/goutils v1.12.3 h1:Wx7i8/a99Cp+Y/XcXgqQr0r9cSsJu7QkWBlKyprTH44=
git.mstar.dev/mstar/goutils v1.12.3/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=

View file

@ -154,7 +154,7 @@ func newServer() {
if *shared.FlagStartDebugServer { if *shared.FlagStartDebugServer {
go func() { go func() {
log.Info().Msg("Starting debug server") log.Info().Msg("Starting debug server")
if err = webdebug.New(*shared.FlagDebugPort).Start(); err != nil { if err = webdebug.New().Start(); err != nil {
log.Fatal().Err(err).Msg("Debug server failed") log.Fatal().Err(err).Msg("Debug server failed")
} }
}() }()

View file

@ -25,11 +25,6 @@ var (
false, false,
"Also start the local debugging server", "Also start the local debugging server",
) )
FlagDebugPort *string = flag.String(
"debugport",
"127.0.0.1:3305",
"Set the address the debug server will listen on. Format: IP:Port",
)
FlagLogFile *string = flag.String( FlagLogFile *string = flag.String(
"logfile", "logfile",
"/var/log/linstrom/logs", "/var/log/linstrom/logs",

View file

@ -8,7 +8,7 @@ import (
webutils "git.mstar.dev/mstar/goutils/http" webutils "git.mstar.dev/mstar/goutils/http"
"git.mstar.dev/mstar/goutils/sliceutils" "git.mstar.dev/mstar/goutils/sliceutils"
"github.com/rs/zerolog/hlog" "github.com/rs/zerolog/log"
"gorm.io/gorm" "gorm.io/gorm"
"git.mstar.dev/mstar/linstrom/storage-new" "git.mstar.dev/mstar/linstrom/storage-new"
@ -22,7 +22,6 @@ func postAs(w http.ResponseWriter, r *http.Request) {
Username string `json:"username"` Username string `json:"username"`
Content string `json:"content"` Content string `json:"content"`
} }
log := hlog.FromRequest(r)
dec := json.NewDecoder(r.Body) dec := json.NewDecoder(r.Body)
data := Inbound{} data := Inbound{}
err := dec.Decode(&data) err := dec.Decode(&data)
@ -77,7 +76,6 @@ func postAs(w http.ResponseWriter, r *http.Request) {
} }
func notesFrom(w http.ResponseWriter, r *http.Request) { func notesFrom(w http.ResponseWriter, r *http.Request) {
log := hlog.FromRequest(r)
username := r.FormValue("username") username := r.FormValue("username")
user, err := dbgen.User.GetByUsername(username) user, err := dbgen.User.GetByUsername(username)
if err != nil { if err != nil {

View file

@ -12,15 +12,15 @@ package webdebug
import ( import (
"context" "context"
"net/http" "net/http"
webutils "git.mstar.dev/mstar/goutils/http"
) )
const DebugAddr = "127.0.0.1:3305"
type Server struct { type Server struct {
server *http.Server server *http.Server
} }
func New(addr string) *Server { func New() *Server {
handler := http.NewServeMux() handler := http.NewServeMux()
handler.HandleFunc("GET /non-deleted", getNonDeletedUsers) handler.HandleFunc("GET /non-deleted", getNonDeletedUsers)
handler.HandleFunc("POST /local-user", createLocalUser) handler.HandleFunc("POST /local-user", createLocalUser)
@ -28,11 +28,8 @@ func New(addr string) *Server {
handler.HandleFunc("POST /post-as", postAs) handler.HandleFunc("POST /post-as", postAs)
handler.HandleFunc("GET /notes-for", notesFrom) handler.HandleFunc("GET /notes-for", notesFrom)
web := http.Server{ web := http.Server{
Addr: addr, Addr: DebugAddr,
Handler: webutils.ChainMiddlewares( Handler: handler,
handler,
webutils.BuildLoggingMiddleware(map[string]string{"server": "debug"}),
),
} }
return &Server{&web} return &Server{&web}
} }

View file

@ -11,7 +11,7 @@ import (
webutils "git.mstar.dev/mstar/goutils/http" webutils "git.mstar.dev/mstar/goutils/http"
"git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/other"
"git.mstar.dev/mstar/goutils/sliceutils" "git.mstar.dev/mstar/goutils/sliceutils"
"github.com/rs/zerolog/hlog" "github.com/rs/zerolog/log"
"git.mstar.dev/mstar/linstrom/shared" "git.mstar.dev/mstar/linstrom/shared"
"git.mstar.dev/mstar/linstrom/storage-new/dbgen" "git.mstar.dev/mstar/linstrom/storage-new/dbgen"
@ -20,38 +20,18 @@ import (
) )
func getNonDeletedUsers(w http.ResponseWriter, r *http.Request) { func getNonDeletedUsers(w http.ResponseWriter, r *http.Request) {
log := hlog.FromRequest(r)
pageStr := r.FormValue("page") pageStr := r.FormValue("page")
page := 0 page := 0
if pageStr != "" { if pageStr != "" {
var err error var err error
page, err = strconv.Atoi(pageStr) page, err = strconv.Atoi(pageStr)
if err != nil { if err != nil {
webutils.ProblemDetails( webutils.HttpErr(w, 0, "page is not a number", http.StatusBadRequest)
w,
http.StatusBadRequest,
"/errors/bad-page",
"bad page number",
other.IntoPointer("page number must be an uint"),
nil,
)
return
}
if page < 0 {
webutils.ProblemDetails(
w,
http.StatusBadRequest,
"/errors/bad-page",
"bad page number",
other.IntoPointer("page number must be >= 0"),
nil,
)
return return
} }
} }
users, err := dbgen.User.GetPagedAllNonDeleted(uint(page)) users, err := dbgen.User.GetPagedAllNonDeleted(uint(page))
if err != nil { if err != nil {
log.Error().Err(err).Int("page", page).Msg("Failed to get non-deleted users")
webutils.ProblemDetails( webutils.ProblemDetails(
w, w,
http.StatusInternalServerError, http.StatusInternalServerError,
@ -78,7 +58,6 @@ func createLocalUser(w http.ResponseWriter, r *http.Request) {
Location *string `json:"location"` Location *string `json:"location"`
IsBot bool `json:"is_bot"` IsBot bool `json:"is_bot"`
} }
log := hlog.FromRequest(r)
jsonDecoder := json.NewDecoder(r.Body) jsonDecoder := json.NewDecoder(r.Body)
data := Inbound{} data := Inbound{}
err := jsonDecoder.Decode(&data) err := jsonDecoder.Decode(&data)

View file

@ -8,61 +8,17 @@ import (
"time" "time"
webutils "git.mstar.dev/mstar/goutils/http" webutils "git.mstar.dev/mstar/goutils/http"
"git.mstar.dev/mstar/goutils/other"
"git.mstar.dev/mstar/goutils/sliceutils"
"github.com/rs/zerolog/hlog" "github.com/rs/zerolog/hlog"
"git.mstar.dev/mstar/linstrom/config" "git.mstar.dev/mstar/linstrom/config"
"git.mstar.dev/mstar/linstrom/storage-new" "git.mstar.dev/mstar/linstrom/storage-new"
"git.mstar.dev/mstar/linstrom/storage-new/dbgen" "git.mstar.dev/mstar/linstrom/storage-new/dbgen"
"git.mstar.dev/mstar/linstrom/storage-new/models"
webshared "git.mstar.dev/mstar/linstrom/web/shared" webshared "git.mstar.dev/mstar/linstrom/web/shared"
) )
var baseLdContext = []any{ var baseLdContext = []any{
"https://www.w3.org/ns/activitystreams", "https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1", "https://w3id.org/security/v1",
map[string]any{
"Key": "sec:Key",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"sensitive": "as:sensitive",
"Hashtag": "as:Hashtag",
"quoteUrl": "as:quoteUrl",
"fedibird": "http://fedibird.com/ns#",
"quoteUri": "fedibird:quoteUri",
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji",
"featured": "toot:featured",
"discoverable": "toot:discoverable",
"indexable": "toot:indexable",
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"misskey": "https://misskey-hub.net/ns#",
"_misskey_content": "misskey:_misskey_content",
"_misskey_quote": "misskey:_misskey_quote",
"_misskey_reaction": "misskey:_misskey_reaction",
"_misskey_votes": "misskey:_misskey_votes",
"_misskey_summary": "misskey:_misskey_summary",
"_misskey_followedMessage": "misskey:_misskey_followedMessage",
"_misskey_requireSigninToViewContents": "misskey:_misskey_requireSigninToViewContents",
"_misskey_makeNotesFollowersOnlyBefore": "misskey:_misskey_makeNotesFollowersOnlyBefore",
"_misskey_makeNotesHiddenBefore": "misskey:_misskey_makeNotesHiddenBefore",
"_misskey_license": "misskey:_misskey_license",
"freeText": map[string]string{
"@id": "misskey:freeText",
"@type": "schema:text",
},
"isCat": "misskey:isCat",
"firefish": "https://joinfirefish.org/ns#",
"speakAsCat": "firefish:speakAsCat",
"sharkey": "https://joinsharkey.org/ns#",
"hideOnlineStatus": "sharkey:hideOnlineStatus",
"backgroundUrl": "sharkey:backgroundUrl",
"listenbrainz": "sharkey:listenbrainz",
"enableRss": "sharkey:enableRss",
"vcard": "http://www.w3.org/2006/vcard/ns#",
},
} }
func users(w http.ResponseWriter, r *http.Request) { func users(w http.ResponseWriter, r *http.Request) {
@ -89,18 +45,11 @@ func users(w http.ResponseWriter, r *http.Request) {
PublicUrl string `json:"url"` PublicUrl string `json:"url"`
Icon *OutboundMedia `json:"icon,omitempty"` Icon *OutboundMedia `json:"icon,omitempty"`
Banner *OutboundMedia `json:"image,omitempty"` Banner *OutboundMedia `json:"image,omitempty"`
Discoverable bool `json:"discoverable"`
Location *string `json:"vcard:Address,omitempty"`
Birthday *string `json:"vcard:bday,omitempty"`
SpeakAsCat bool `json:"speakAsCat"`
IsCat bool `json:"isCat"`
RestrictedFollow bool `json:"manuallyApprovesFollowers"`
} }
log := hlog.FromRequest(r) log := hlog.FromRequest(r)
userId := r.PathValue("id") userId := r.PathValue("id")
user, err := dbgen.User.Where(dbgen.User.ID.Eq(userId)). user, err := dbgen.User.Where(dbgen.User.ID.Eq(userId)).
Preload(dbgen.User.Icon).Preload(dbgen.User.Banner). Preload(dbgen.User.Icon).Preload(dbgen.User.Banner).
Preload(dbgen.User.BeingTypes).
First() First()
if err != nil { if err != nil {
webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil) webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil)
@ -133,8 +82,6 @@ func users(w http.ResponseWriter, r *http.Request) {
Published: user.CreatedAt, Published: user.CreatedAt,
DisplayName: user.DisplayName, DisplayName: user.DisplayName,
PublicUrl: config.GlobalConfig.General.GetFullPublicUrl() + "/user/" + user.Username, PublicUrl: config.GlobalConfig.General.GetFullPublicUrl() + "/user/" + user.Username,
Discoverable: user.Indexable,
RestrictedFollow: user.RestrictedFollow,
} }
if user.Description != "" { if user.Description != "" {
data.Description = &user.Description data.Description = &user.Description
@ -155,18 +102,6 @@ func users(w http.ResponseWriter, r *http.Request) {
MediaType: user.Banner.Type, MediaType: user.Banner.Type,
} }
} }
if sliceutils.ContainsFunc(user.BeingTypes, func(t models.UserToBeing) bool {
return t.Being == models.BEING_CAT
}) {
data.IsCat = true
// data.SpeakAsCat = true // TODO: Move to check of separate field in db model
}
if user.Location.Valid {
data.Location = &user.Location.String
}
if user.Birthday.Valid {
data.Birthday = other.IntoPointer(user.Birthday.Time.Format("2006-Jan-02")) //YYYY-Month-DD
}
encoded, err := json.Marshal(data) encoded, err := json.Marshal(data)
w.Header().Add("Content-Type", "application/activity+json") w.Header().Add("Content-Type", "application/activity+json")

View file

@ -8,7 +8,7 @@ import (
webutils "git.mstar.dev/mstar/goutils/http" webutils "git.mstar.dev/mstar/goutils/http"
"git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/other"
"github.com/rs/zerolog/hlog" "github.com/rs/zerolog/log"
"gorm.io/gorm" "gorm.io/gorm"
"git.mstar.dev/mstar/linstrom/config" "git.mstar.dev/mstar/linstrom/config"
@ -30,7 +30,6 @@ func WellKnownWebfinger(w http.ResponseWriter, r *http.Request) {
Links []OutboundLink `json:"links"` Links []OutboundLink `json:"links"`
Aliases []string `json:"aliases,omitempty"` Aliases []string `json:"aliases,omitempty"`
} }
log := hlog.FromRequest(r)
requestedResource := r.FormValue("resource") requestedResource := r.FormValue("resource")
matches := webfingerResourceRegex.FindStringSubmatch(requestedResource) matches := webfingerResourceRegex.FindStringSubmatch(requestedResource)
if len(matches) == 0 { if len(matches) == 0 {
@ -105,7 +104,6 @@ func WellKnownWebfinger(w http.ResponseWriter, r *http.Request) {
func Nodeinfo(w http.ResponseWriter, r *http.Request) { func Nodeinfo(w http.ResponseWriter, r *http.Request) {
u := dbgen.User u := dbgen.User
log := hlog.FromRequest(r)
userCount, err := u.Where(u.DeletedAt.IsNull(), u.Verified.Is(true)).Count() userCount, err := u.Where(u.DeletedAt.IsNull(), u.Verified.Is(true)).Count()
if err != nil { if err != nil {
webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil) webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil)

View file

@ -11,7 +11,6 @@ var errorDescriptions = map[string]string{
"webfinger-bad-resource": "The given format for the \"resource\" url parameter was missing or invalid. It must follow the form \"acct:<username>@<domain>\"", "webfinger-bad-resource": "The given format for the \"resource\" url parameter was missing or invalid. It must follow the form \"acct:<username>@<domain>\"",
"db-failure": "The database query for this request failed for an undisclosed reason. This is often caused by bad input data conflicting with existing information. Try to submit different data or wait for some time", "db-failure": "The database query for this request failed for an undisclosed reason. This is often caused by bad input data conflicting with existing information. Try to submit different data or wait for some time",
"bad-request-data": "The data provided in the request doesn't match the requirements, see problem details' detail field for more information", "bad-request-data": "The data provided in the request doesn't match the requirements, see problem details' detail field for more information",
"bad-page": "The provided page number was not valid. See response details for more information",
} }
func errorTypeHandler(w http.ResponseWriter, r *http.Request) { func errorTypeHandler(w http.ResponseWriter, r *http.Request) {

View file

@ -57,10 +57,7 @@ func New(addr string, duckImg *string) *Server {
fmt.Fprint(w, *duckImg) fmt.Fprint(w, *duckImg)
}) })
server := http.Server{ server := http.Server{
Handler: webutils.ChainMiddlewares( Handler: webutils.ChainMiddlewares(handler, webutils.LoggingMiddleware),
handler,
webutils.BuildLoggingMiddleware(map[string]string{"server": "public"}),
),
Addr: addr, Addr: addr,
} }
return &Server{&server} return &Server{&server}

View file

@ -19,7 +19,6 @@ type User struct {
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
ServerId uint `json:"server_id"` ServerId uint `json:"server_id"`
Displayname string `json:"displayname"` Displayname string `json:"displayname"`
Username string `json:"username"`
Description string `json:"description"` Description string `json:"description"`
IsBot bool `json:"is_bot"` IsBot bool `json:"is_bot"`
IconId *string `json:"icon_id"` IconId *string `json:"icon_id"`
@ -89,7 +88,6 @@ func (u *User) FromModel(m *models.User) {
u.ServerId = m.ServerId u.ServerId = m.ServerId
u.Displayname = m.DisplayName u.Displayname = m.DisplayName
u.IsBot = m.IsBot u.IsBot = m.IsBot
u.Username = m.Username
if m.IconId.Valid { if m.IconId.Valid {
u.IconId = &m.IconId.String u.IconId = &m.IconId.String
} }