mirror of
https://github.com/pushbits/server.git
synced 2025-05-03 20:26:23 +02:00
Merge remote-tracking branch 'origin/main' into alertmanager-interface
This commit is contained in:
commit
d1c62e24ed
26 changed files with 301 additions and 107 deletions
60
.github/workflows/publish.yml
vendored
60
.github/workflows/publish.yml
vendored
|
@ -5,17 +5,10 @@ on:
|
||||||
tags:
|
tags:
|
||||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: ${{ github.repository }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test_build_publish:
|
test:
|
||||||
name: Test, build, and publish
|
name: Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
@ -36,6 +29,22 @@ jobs:
|
||||||
source $(poetry env info --path)/bin/activate
|
source $(poetry env info --path)/bin/activate
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
publish_docker_image:
|
||||||
|
name: Publish Docker image
|
||||||
|
needs: test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: ${{ github.repository }}
|
||||||
|
steps:
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
|
@ -49,12 +58,41 @@ jobs:
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest
|
type=semver,pattern={{major}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
|
||||||
push: true
|
push: true
|
||||||
|
build-args: PB_BUILD_VERSION=${{ github.ref_name }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
publish_github_release:
|
||||||
|
name: Publish GitHub Release
|
||||||
|
needs: test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Export GOBIN
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v2
|
||||||
|
with:
|
||||||
|
distribution: goreleaser
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name: Main
|
name: Test
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
@ -32,3 +32,6 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
source $(poetry env info --path)/bin/activate
|
source $(poetry env info --path)/bin/activate
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make build
|
19
.goreleaser.yml
Normal file
19
.goreleaser.yml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
builds:
|
||||||
|
- id: pushbits
|
||||||
|
main: ./cmd/pushbits
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
ldflags:
|
||||||
|
- -s -w -X main.version=v{{.Version}}
|
||||||
|
|
||||||
|
checksum:
|
||||||
|
algorithm: sha256
|
||||||
|
|
||||||
|
archives:
|
||||||
|
- id: pushbits
|
||||||
|
builds:
|
||||||
|
- pushbits
|
||||||
|
format: tar.gz
|
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/pushbits",
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
FROM docker.io/library/golang:alpine as builder
|
FROM docker.io/library/golang:alpine as builder
|
||||||
|
|
||||||
|
ARG PB_BUILD_VERSION
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
@ -8,7 +10,7 @@ RUN set -ex \
|
||||||
&& apk add --no-cache build-base \
|
&& apk add --no-cache build-base \
|
||||||
&& go mod download \
|
&& go mod download \
|
||||||
&& go mod verify \
|
&& go mod verify \
|
||||||
&& make build \
|
&& PB_BUILD_VERSION="$PB_BUILD_VERSION" make build \
|
||||||
&& chmod +x /build/out/pushbits
|
&& chmod +x /build/out/pushbits
|
||||||
|
|
||||||
FROM docker.io/library/alpine
|
FROM docker.io/library/alpine
|
||||||
|
|
9
Makefile
9
Makefile
|
@ -5,12 +5,17 @@ DOCS_DIR := ./docs
|
||||||
OUT_DIR := ./out
|
OUT_DIR := ./out
|
||||||
TESTS_DIR := ./tests
|
TESTS_DIR := ./tests
|
||||||
|
|
||||||
|
PB_BUILD_VERSION ?= $(shell git describe --tags)
|
||||||
|
ifeq ($(PB_BUILD_VERSION),)
|
||||||
|
_ := $(error Cannot determine build version)
|
||||||
|
endif
|
||||||
|
|
||||||
SEMGREP_MODFILE := $(TESTS_DIR)/semgrep-rules/go.mod
|
SEMGREP_MODFILE := $(TESTS_DIR)/semgrep-rules/go.mod
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
mkdir -p $(OUT_DIR)
|
mkdir -p $(OUT_DIR)
|
||||||
go build -ldflags="-w -s" -o $(OUT_DIR)/pushbits ./cmd/pushbits
|
go build -ldflags="-w -s -X main.version=$(PB_BUILD_VERSION)" -o $(OUT_DIR)/pushbits ./cmd/pushbits
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
@ -37,7 +42,7 @@ setup:
|
||||||
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
|
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
|
||||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
go install honnef.co/go/tools/cmd/staticcheck@v0.2.2
|
||||||
poetry install
|
poetry install
|
||||||
|
|
||||||
.PHONY: swag
|
.PHONY: swag
|
||||||
|
|
|
@ -72,7 +72,7 @@ This project totally would've used Signal if it would offer a proper API.
|
||||||
Sadly, neither [Signal](https://signal.org/) nor [WhatsApp](https://www.whatsapp.com/) come with an API (at the time of writing) through which PushBits could interact.
|
Sadly, neither [Signal](https://signal.org/) nor [WhatsApp](https://www.whatsapp.com/) come with an API (at the time of writing) through which PushBits could interact.
|
||||||
|
|
||||||
In [Telegram](https://telegram.org/) there is an API to run bots, but these are limited in that they cannot create chats by themselves.
|
In [Telegram](https://telegram.org/) there is an API to run bots, but these are limited in that they cannot create chats by themselves.
|
||||||
If you insist on going with Telegram, have a look at [webhook2telegram](https://github.com/muety/webhook2telegram).
|
If you insist on going with Telegram, have a look at [telepush](https://github.com/muety/telepush).
|
||||||
|
|
||||||
The idea of a federated, synchronized but yet end-to-end encrypted protocol is awesome, but its clients simply aren't really there yet.
|
The idea of a federated, synchronized but yet end-to-end encrypted protocol is awesome, but its clients simply aren't really there yet.
|
||||||
Still, if you haven't tried it yet, we'd encourage you to check it out.
|
Still, if you haven't tried it yet, we'd encourage you to check it out.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -10,10 +9,13 @@ import (
|
||||||
"github.com/pushbits/server/internal/configuration"
|
"github.com/pushbits/server/internal/configuration"
|
||||||
"github.com/pushbits/server/internal/database"
|
"github.com/pushbits/server/internal/database"
|
||||||
"github.com/pushbits/server/internal/dispatcher"
|
"github.com/pushbits/server/internal/dispatcher"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/router"
|
"github.com/pushbits/server/internal/router"
|
||||||
"github.com/pushbits/server/internal/runner"
|
"github.com/pushbits/server/internal/runner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var version string
|
||||||
|
|
||||||
func setupCleanup(db *database.Database, dp *dispatcher.Dispatcher) {
|
func setupCleanup(db *database.Database, dp *dispatcher.Dispatcher) {
|
||||||
c := make(chan os.Signal)
|
c := make(chan os.Signal)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
@ -30,41 +32,46 @@ func setupCleanup(db *database.Database, dp *dispatcher.Dispatcher) {
|
||||||
// @version 0.7.2
|
// @version 0.7.2
|
||||||
// @description Documentation for the PushBits server API.
|
// @description Documentation for the PushBits server API.
|
||||||
|
|
||||||
// @contact.name PushBits
|
// @contact.name The PushBits Developers
|
||||||
// @contact.url https://www.pushbits.io
|
// @contact.url https://www.pushbits.io
|
||||||
|
|
||||||
// @license.name ISC
|
// @license.name ISC
|
||||||
// @license.url https://github.com/pushbits/server/blob/master/LICENSE
|
// @license.url https://github.com/pushbits/server/blob/master/LICENSE
|
||||||
|
|
||||||
// @host your-domain.net
|
|
||||||
// @BasePath /
|
// @BasePath /
|
||||||
// @query.collection.format multi
|
// @query.collection.format multi
|
||||||
|
// @schemes http https
|
||||||
|
|
||||||
// @securityDefinitions.basic BasicAuth
|
// @securityDefinitions.basic BasicAuth
|
||||||
func main() {
|
func main() {
|
||||||
log.Println("Starting PushBits.")
|
if len(version) == 0 {
|
||||||
|
log.L.Panic("Version not set")
|
||||||
|
} else {
|
||||||
|
log.L.Printf("Starting PushBits %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
c := configuration.Get()
|
c := configuration.Get()
|
||||||
|
|
||||||
if c.Debug {
|
if c.Debug {
|
||||||
log.Printf("%+v", c)
|
log.SetDebug()
|
||||||
|
log.L.Printf("%+v", c)
|
||||||
}
|
}
|
||||||
|
|
||||||
cm := credentials.CreateManager(c.Security.CheckHIBP, c.Crypto)
|
cm := credentials.CreateManager(c.Security.CheckHIBP, c.Crypto)
|
||||||
|
|
||||||
db, err := database.Create(cm, c.Database.Dialect, c.Database.Connection)
|
db, err := database.Create(cm, c.Database.Dialect, c.Database.Connection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
if err := db.Populate(c.Admin.Name, c.Admin.Password, c.Admin.MatrixID); err != nil {
|
if err := db.Populate(c.Admin.Name, c.Admin.Password, c.Admin.MatrixID); err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dp, err := dispatcher.Create(c.Matrix.Homeserver, c.Matrix.Username, c.Matrix.Password, c.Formatting)
|
dp, err := dispatcher.Create(c.Matrix.Homeserver, c.Matrix.Username, c.Matrix.Password, c.Formatting)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
}
|
}
|
||||||
defer dp.Close()
|
defer dp.Close()
|
||||||
|
|
||||||
|
@ -72,13 +79,13 @@ func main() {
|
||||||
|
|
||||||
err = db.RepairChannels(dp)
|
err = db.RepairChannels(dp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
engine := router.Create(c.Debug, cm, db, dp, &c.Alertmanager)
|
engine := router.Create(c.Debug, cm, db, dp, &c.Alertmanager)
|
||||||
|
|
||||||
err = runner.Run(engine, c.HTTP.ListenAddress, c.HTTP.Port)
|
err = runner.Run(engine, c.HTTP.ListenAddress, c.HTTP.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -14,6 +14,7 @@ require (
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/ugorji/go v1.2.4 // indirect
|
github.com/ugorji/go v1.2.4 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -95,7 +95,10 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
|
|
@ -2,10 +2,10 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/authentication"
|
"github.com/pushbits/server/internal/authentication"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/model"
|
"github.com/pushbits/server/internal/model"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -27,7 +27,7 @@ func (h *ApplicationHandler) generateToken(compat bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApplicationHandler) registerApplication(ctx *gin.Context, a *model.Application, u *model.User) error {
|
func (h *ApplicationHandler) registerApplication(ctx *gin.Context, a *model.Application, u *model.User) error {
|
||||||
log.Printf("Registering application %s.", a.Name)
|
log.L.Printf("Registering application %s.", a.Name)
|
||||||
|
|
||||||
channelID, err := h.DP.RegisterApplication(a.ID, a.Name, a.Token, u.MatrixID)
|
channelID, err := h.DP.RegisterApplication(a.ID, a.Name, a.Token, u.MatrixID)
|
||||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||||
|
@ -45,7 +45,7 @@ func (h *ApplicationHandler) registerApplication(ctx *gin.Context, a *model.Appl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApplicationHandler) createApplication(ctx *gin.Context, u *model.User, name string, compat bool) (*model.Application, error) {
|
func (h *ApplicationHandler) createApplication(ctx *gin.Context, u *model.User, name string, compat bool) (*model.Application, error) {
|
||||||
log.Printf("Creating application %s.", name)
|
log.L.Printf("Creating application %s.", name)
|
||||||
|
|
||||||
application := model.Application{}
|
application := model.Application{}
|
||||||
application.Name = name
|
application.Name = name
|
||||||
|
@ -60,7 +60,7 @@ func (h *ApplicationHandler) createApplication(ctx *gin.Context, u *model.User,
|
||||||
if err := h.registerApplication(ctx, &application, u); err != nil {
|
if err := h.registerApplication(ctx, &application, u); err != nil {
|
||||||
err := h.DB.DeleteApplication(&application)
|
err := h.DB.DeleteApplication(&application)
|
||||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||||
log.Printf("Cannot delete application with ID %d.", application.ID)
|
log.L.Printf("Cannot delete application with ID %d.", application.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -70,7 +70,7 @@ func (h *ApplicationHandler) createApplication(ctx *gin.Context, u *model.User,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApplicationHandler) deleteApplication(ctx *gin.Context, a *model.Application, u *model.User) error {
|
func (h *ApplicationHandler) deleteApplication(ctx *gin.Context, a *model.Application, u *model.User) error {
|
||||||
log.Printf("Deleting application %s (ID %d).", a.Name, a.ID)
|
log.L.Printf("Deleting application %s (ID %d).", a.Name, a.ID)
|
||||||
|
|
||||||
err := h.DP.DeregisterApplication(a, u)
|
err := h.DP.DeregisterApplication(a, u)
|
||||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||||
|
@ -86,15 +86,15 @@ func (h *ApplicationHandler) deleteApplication(ctx *gin.Context, a *model.Applic
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApplicationHandler) updateApplication(ctx *gin.Context, a *model.Application, updateApplication *model.UpdateApplication) error {
|
func (h *ApplicationHandler) updateApplication(ctx *gin.Context, a *model.Application, updateApplication *model.UpdateApplication) error {
|
||||||
log.Printf("Updating application %s (ID %d).", a.Name, a.ID)
|
log.L.Printf("Updating application %s (ID %d).", a.Name, a.ID)
|
||||||
|
|
||||||
if updateApplication.Name != nil {
|
if updateApplication.Name != nil {
|
||||||
log.Printf("Updating application name to '%s'.", *updateApplication.Name)
|
log.L.Printf("Updating application name to '%s'.", *updateApplication.Name)
|
||||||
a.Name = *updateApplication.Name
|
a.Name = *updateApplication.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
if updateApplication.RefreshToken != nil && (*updateApplication.RefreshToken) {
|
if updateApplication.RefreshToken != nil && (*updateApplication.RefreshToken) {
|
||||||
log.Print("Updating application token.")
|
log.L.Print("Updating application token.")
|
||||||
compat := updateApplication.StrictCompatibility != nil && (*updateApplication.StrictCompatibility)
|
compat := updateApplication.StrictCompatibility != nil && (*updateApplication.StrictCompatibility)
|
||||||
a.Token = h.generateToken(compat)
|
a.Token = h.generateToken(compat)
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) {
|
||||||
var createApplication model.CreateApplication
|
var createApplication model.CreateApplication
|
||||||
|
|
||||||
if err := ctx.Bind(&createApplication); err != nil {
|
if err := ctx.Bind(&createApplication); err != nil {
|
||||||
log.Println(err)
|
log.L.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -12,6 +11,7 @@ import (
|
||||||
"github.com/pushbits/server/internal/authentication/credentials"
|
"github.com/pushbits/server/internal/authentication/credentials"
|
||||||
"github.com/pushbits/server/internal/configuration"
|
"github.com/pushbits/server/internal/configuration"
|
||||||
"github.com/pushbits/server/internal/database"
|
"github.com/pushbits/server/internal/database"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/model"
|
"github.com/pushbits/server/internal/model"
|
||||||
"github.com/pushbits/server/tests"
|
"github.com/pushbits/server/tests"
|
||||||
"github.com/pushbits/server/tests/mockups"
|
"github.com/pushbits/server/tests/mockups"
|
||||||
|
@ -50,7 +50,7 @@ func TestMain(m *testing.M) {
|
||||||
db, err := mockups.GetEmptyDatabase(config.Crypto)
|
db, err := mockups.GetEmptyDatabase(config.Crypto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanUp()
|
cleanUp()
|
||||||
log.Println("Can not set up database: ", err)
|
log.L.Println("Can not set up database: ", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
TestDatabase = db
|
TestDatabase = db
|
||||||
|
@ -58,7 +58,7 @@ func TestMain(m *testing.M) {
|
||||||
appHandler, err := getApplicationHandler(config)
|
appHandler, err := getApplicationHandler(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanUp()
|
cleanUp()
|
||||||
log.Println("Can not set up application handler: ", err)
|
log.L.Println("Can not set up application handler: ", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ func TestMain(m *testing.M) {
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
m.Run()
|
m.Run()
|
||||||
log.Println("Clean up after Test")
|
log.L.Println("Clean up after Test")
|
||||||
cleanUp()
|
cleanUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/authentication"
|
"github.com/pushbits/server/internal/authentication"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/model"
|
"github.com/pushbits/server/internal/model"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -45,7 +45,7 @@ type NotificationHandler struct {
|
||||||
// @Router /message [post]
|
// @Router /message [post]
|
||||||
func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
||||||
application := authentication.GetApplication(ctx)
|
application := authentication.GetApplication(ctx)
|
||||||
log.Printf("Sending notification for application %s.", application.Name)
|
log.L.Printf("Sending notification for application %s.", application.Name)
|
||||||
|
|
||||||
var notification model.Notification
|
var notification model.Notification
|
||||||
if err := ctx.Bind(¬ification); err != nil {
|
if err := ctx.Bind(¬ification); err != nil {
|
||||||
|
@ -79,7 +79,7 @@ func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
||||||
// @Router /message/{message_id} [DELETE]
|
// @Router /message/{message_id} [DELETE]
|
||||||
func (h *NotificationHandler) DeleteNotification(ctx *gin.Context) {
|
func (h *NotificationHandler) DeleteNotification(ctx *gin.Context) {
|
||||||
application := authentication.GetApplication(ctx)
|
application := authentication.GetApplication(ctx)
|
||||||
log.Printf("Deleting notification for application %s.", application.Name)
|
log.L.Printf("Deleting notification for application %s.", application.Name)
|
||||||
|
|
||||||
id, err := getMessageID(ctx)
|
id, err := getMessageID(ctx)
|
||||||
if success := successOrAbort(ctx, http.StatusUnprocessableEntity, err); !success {
|
if success := successOrAbort(ctx, http.StatusUnprocessableEntity, err); !success {
|
||||||
|
|
|
@ -2,10 +2,10 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/authentication"
|
"github.com/pushbits/server/internal/authentication"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/model"
|
"github.com/pushbits/server/internal/model"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -90,7 +90,7 @@ func (h *UserHandler) updateUser(ctx *gin.Context, u *model.User, updateUser mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Updating user %s.", u.Name)
|
log.L.Printf("Updating user %s.", u.Name)
|
||||||
|
|
||||||
if updateUser.Name != nil {
|
if updateUser.Name != nil {
|
||||||
u.Name = *updateUser.Name
|
u.Name = *updateUser.Name
|
||||||
|
@ -146,7 +146,7 @@ func (h *UserHandler) CreateUser(ctx *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Creating user %s.", createUser.Name)
|
log.L.Printf("Creating user %s.", createUser.Name)
|
||||||
|
|
||||||
user, err := h.DB.CreateUser(createUser)
|
user, err := h.DB.CreateUser(createUser)
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ func (h *UserHandler) DeleteUser(ctx *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Deleting user %s.", user.Name)
|
log.L.Printf("Deleting user %s.", user.Name)
|
||||||
|
|
||||||
if err := h.deleteApplications(ctx, user); err != nil {
|
if err := h.deleteApplications(ctx, user); err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package credentials
|
package credentials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/configuration"
|
"github.com/pushbits/server/internal/configuration"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
|
|
||||||
"github.com/alexedwards/argon2id"
|
"github.com/alexedwards/argon2id"
|
||||||
)
|
)
|
||||||
|
@ -16,7 +15,7 @@ type Manager struct {
|
||||||
|
|
||||||
// CreateManager instanciates a credential manager.
|
// CreateManager instanciates a credential manager.
|
||||||
func CreateManager(checkHIBP bool, c configuration.CryptoConfig) *Manager {
|
func CreateManager(checkHIBP bool, c configuration.CryptoConfig) *Manager {
|
||||||
log.Println("Setting up credential manager.")
|
log.L.Println("Setting up credential manager.")
|
||||||
|
|
||||||
argon2Params := &argon2id.Params{
|
argon2Params := &argon2id.Params{
|
||||||
Memory: c.Argon2.Memory,
|
Memory: c.Argon2.Memory,
|
||||||
|
|
|
@ -4,9 +4,10 @@ import (
|
||||||
"crypto/sha1" //#nosec G505 -- False positive, see the use below.
|
"crypto/sha1" //#nosec G505 -- False positive, see the use below.
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -27,7 +28,7 @@ func IsPasswordPwned(password string) (bool, error) {
|
||||||
lookup := hashStr[0:5]
|
lookup := hashStr[0:5]
|
||||||
match := hashStr[5:]
|
match := hashStr[5:]
|
||||||
|
|
||||||
log.Printf("Checking HIBP for hashes starting with '%s'.", lookup)
|
log.L.Printf("Checking HIBP for hashes starting with '%s'.", lookup)
|
||||||
|
|
||||||
resp, err := http.Get(pwnedHashesURL + lookup)
|
resp, err := http.Get(pwnedHashesURL + lookup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,13 +36,13 @@ func IsPasswordPwned(password string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
log.Fatalf("Request failed with HTTP %s.", resp.Status)
|
log.L.Fatalf("Request failed with HTTP %s.", resp.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
bodyText, err := ioutil.ReadAll(resp.Body)
|
bodyText, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyStr := string(bodyText)
|
bodyStr := string(bodyText)
|
||||||
|
|
|
@ -2,9 +2,10 @@ package credentials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/alexedwards/argon2id"
|
"github.com/alexedwards/argon2id"
|
||||||
|
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreatePasswordHash returns a hashed version of the given password.
|
// CreatePasswordHash returns a hashed version of the given password.
|
||||||
|
@ -21,7 +22,7 @@ func (m *Manager) CreatePasswordHash(password string) ([]byte, error) {
|
||||||
hash, err := argon2id.CreateHash(password, m.argon2Params)
|
hash, err := argon2id.CreateHash(password, m.argon2Params)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ func ComparePassword(hash, password []byte) bool {
|
||||||
match, err := argon2id.ComparePasswordAndHash(string(password), string(hash))
|
match, err := argon2id.ComparePasswordAndHash(string(password), string(hash))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.L.Fatal(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,12 @@ package database
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/authentication/credentials"
|
"github.com/pushbits/server/internal/authentication/credentials"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/model"
|
"github.com/pushbits/server/internal/model"
|
||||||
|
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
|
@ -36,7 +36,7 @@ func createFileDir(file string) {
|
||||||
|
|
||||||
// Create instanciates a database connection.
|
// Create instanciates a database connection.
|
||||||
func Create(cm *credentials.Manager, dialect, connection string) (*Database, error) {
|
func Create(cm *credentials.Manager, dialect, connection string) (*Database, error) {
|
||||||
log.Println("Setting up database connection.")
|
log.L.Println("Setting up database connection.")
|
||||||
|
|
||||||
maxOpenConns := 5
|
maxOpenConns := 5
|
||||||
|
|
||||||
|
@ -82,13 +82,13 @@ func Create(cm *credentials.Manager, dialect, connection string) (*Database, err
|
||||||
func (d *Database) Close() {
|
func (d *Database) Close() {
|
||||||
err := d.sqldb.Close()
|
err := d.sqldb.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error while closing database: %s", err)
|
log.L.Printf("Error while closing database: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate fills the database with initial information like the admin user.
|
// Populate fills the database with initial information like the admin user.
|
||||||
func (d *Database) Populate(name, password, matrixID string) error {
|
func (d *Database) Populate(name, password, matrixID string) error {
|
||||||
log.Print("Populating database.")
|
log.L.Print("Populating database.")
|
||||||
|
|
||||||
var user model.User
|
var user model.User
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ func (d *Database) Populate(name, password, matrixID string) error {
|
||||||
return errors.New("user cannot be created")
|
return errors.New("user cannot be created")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Priviledged user %s already exists.", name)
|
log.L.Printf("Priviledged user %s already exists.", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -112,7 +112,7 @@ func (d *Database) Populate(name, password, matrixID string) error {
|
||||||
|
|
||||||
// RepairChannels resets channels that have been modified by a user.
|
// RepairChannels resets channels that have been modified by a user.
|
||||||
func (d *Database) RepairChannels(dp Dispatcher) error {
|
func (d *Database) RepairChannels(dp Dispatcher) error {
|
||||||
log.Print("Repairing application channels.")
|
log.L.Print("Repairing application channels.")
|
||||||
|
|
||||||
users, err := d.GetUsers()
|
users, err := d.GetUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -140,11 +140,11 @@ func (d *Database) RepairChannels(dp Dispatcher) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if orphan {
|
if orphan {
|
||||||
log.Printf("Found orphan channel for application %s (ID %d)", application.Name, application.ID)
|
log.L.Printf("Found orphan channel for application %s (ID %d)", application.Name, application.ID)
|
||||||
|
|
||||||
if err = dp.RepairApplication(&application, &user); err != nil {
|
if err = dp.RepairApplication(&application, &user); err != nil {
|
||||||
log.Printf("Unable to repair application %s (ID %d).", application.Name, application.ID)
|
log.L.Printf("Unable to repair application %s (ID %d).", application.Name, application.ID)
|
||||||
log.Println(err)
|
log.L.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ package dispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/pushbits/server/internal/model"
|
"github.com/pushbits/server/internal/model"
|
||||||
"maunium.net/go/mautrix"
|
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
mId "maunium.net/go/mautrix/id"
|
mId "maunium.net/go/mautrix/id"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +17,7 @@ func buildRoomTopic(id uint) string {
|
||||||
|
|
||||||
// RegisterApplication creates a channel for an application.
|
// RegisterApplication creates a channel for an application.
|
||||||
func (d *Dispatcher) RegisterApplication(id uint, name, token, user string) (string, error) {
|
func (d *Dispatcher) RegisterApplication(id uint, name, token, user string) (string, error) {
|
||||||
log.Printf("Registering application %s, notifications will be relayed to user %s.\n", name, user)
|
log.L.Printf("Registering application %s, notifications will be relayed to user %s.\n", name, user)
|
||||||
|
|
||||||
resp, err := d.mautrixClient.CreateRoom(&mautrix.ReqCreateRoom{
|
resp, err := d.mautrixClient.CreateRoom(&mautrix.ReqCreateRoom{
|
||||||
Visibility: "private",
|
Visibility: "private",
|
||||||
|
@ -28,18 +28,18 @@ func (d *Dispatcher) RegisterApplication(id uint, name, token, user string) (str
|
||||||
Topic: buildRoomTopic(id),
|
Topic: buildRoomTopic(id),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.L.Print(err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Application %s is now relayed to room with ID %s.\n", name, resp.RoomID.String())
|
log.L.Printf("Application %s is now relayed to room with ID %s.\n", name, resp.RoomID.String())
|
||||||
|
|
||||||
return resp.RoomID.String(), err
|
return resp.RoomID.String(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeregisterApplication deletes a channel for an application.
|
// DeregisterApplication deletes a channel for an application.
|
||||||
func (d *Dispatcher) DeregisterApplication(a *model.Application, u *model.User) error {
|
func (d *Dispatcher) DeregisterApplication(a *model.Application, u *model.User) error {
|
||||||
log.Printf("Deregistering application %s (ID %d) with Matrix ID %s.\n", a.Name, a.ID, a.MatrixID)
|
log.L.Printf("Deregistering application %s (ID %d) with Matrix ID %s.\n", a.Name, a.ID, a.MatrixID)
|
||||||
|
|
||||||
// The user might have left the channel, but we can still try to remove them.
|
// The user might have left the channel, but we can still try to remove them.
|
||||||
|
|
||||||
|
@ -47,17 +47,17 @@ func (d *Dispatcher) DeregisterApplication(a *model.Application, u *model.User)
|
||||||
Reason: "This application was deleted",
|
Reason: "This application was deleted",
|
||||||
UserID: mId.UserID(u.MatrixID),
|
UserID: mId.UserID(u.MatrixID),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Print(err)
|
log.L.Print(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := d.mautrixClient.LeaveRoom(mId.RoomID(a.MatrixID)); err != nil {
|
if _, err := d.mautrixClient.LeaveRoom(mId.RoomID(a.MatrixID)); err != nil {
|
||||||
log.Print(err)
|
log.L.Print(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := d.mautrixClient.ForgetRoom(mId.RoomID(a.MatrixID)); err != nil {
|
if _, err := d.mautrixClient.ForgetRoom(mId.RoomID(a.MatrixID)); err != nil {
|
||||||
log.Print(err)
|
log.L.Print(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ func (d *Dispatcher) DeregisterApplication(a *model.Application, u *model.User)
|
||||||
|
|
||||||
func (d *Dispatcher) sendRoomEvent(roomID, eventType string, content interface{}) error {
|
func (d *Dispatcher) sendRoomEvent(roomID, eventType string, content interface{}) error {
|
||||||
if _, err := d.mautrixClient.SendStateEvent(mId.RoomID(roomID), event.NewEventType(eventType), "", content); err != nil {
|
if _, err := d.mautrixClient.SendStateEvent(mId.RoomID(roomID), event.NewEventType(eventType), "", content); err != nil {
|
||||||
log.Print(err)
|
log.L.Print(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ func (d *Dispatcher) sendRoomEvent(roomID, eventType string, content interface{}
|
||||||
|
|
||||||
// UpdateApplication updates a channel for an application.
|
// UpdateApplication updates a channel for an application.
|
||||||
func (d *Dispatcher) UpdateApplication(a *model.Application) error {
|
func (d *Dispatcher) UpdateApplication(a *model.Application) error {
|
||||||
log.Printf("Updating application %s (ID %d) with Matrix ID %s.\n", a.Name, a.ID, a.MatrixID)
|
log.L.Printf("Updating application %s (ID %d) with Matrix ID %s.\n", a.Name, a.ID, a.MatrixID)
|
||||||
|
|
||||||
content := map[string]interface{}{
|
content := map[string]interface{}{
|
||||||
"name": a.Name,
|
"name": a.Name,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package dispatcher
|
package dispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/configuration"
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
|
|
||||||
|
"github.com/pushbits/server/internal/configuration"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dispatcher holds information for sending notifications to clients.
|
// Dispatcher holds information for sending notifications to clients.
|
||||||
|
@ -16,7 +16,7 @@ type Dispatcher struct {
|
||||||
|
|
||||||
// Create instanciates a dispatcher connection.
|
// Create instanciates a dispatcher connection.
|
||||||
func Create(homeserver, username, password string, formatting configuration.Formatting) (*Dispatcher, error) {
|
func Create(homeserver, username, password string, formatting configuration.Formatting) (*Dispatcher, error) {
|
||||||
log.Println("Setting up dispatcher.")
|
log.L.Println("Setting up dispatcher.")
|
||||||
|
|
||||||
matrixClient, err := mautrix.NewClient(homeserver, "", "")
|
matrixClient, err := mautrix.NewClient(homeserver, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -39,14 +39,14 @@ func Create(homeserver, username, password string, formatting configuration.Form
|
||||||
|
|
||||||
// Close closes the dispatcher connection.
|
// Close closes the dispatcher connection.
|
||||||
func (d *Dispatcher) Close() {
|
func (d *Dispatcher) Close() {
|
||||||
log.Printf("Logging out.")
|
log.L.Printf("Logging out.")
|
||||||
|
|
||||||
_, err := d.mautrixClient.Logout()
|
_, err := d.mautrixClient.Logout()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error while logging out: %s", err)
|
log.L.Printf("Error while logging out: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.mautrixClient.ClearCredentials()
|
d.mautrixClient.ClearCredentials()
|
||||||
|
|
||||||
log.Printf("Successfully logged out.")
|
log.L.Printf("Successfully logged out.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,16 @@ package dispatcher
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"log"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
"github.com/pushbits/server/internal/model"
|
|
||||||
"github.com/pushbits/server/internal/pberrors"
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
mId "maunium.net/go/mautrix/id"
|
mId "maunium.net/go/mautrix/id"
|
||||||
|
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
|
"github.com/pushbits/server/internal/model"
|
||||||
|
"github.com/pushbits/server/internal/pberrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MessageFormat is a matrix message format
|
// MessageFormat is a matrix message format
|
||||||
|
@ -31,9 +32,9 @@ type MessageEvent struct {
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
FormattedBody string `json:"formatted_body"`
|
FormattedBody string `json:"formatted_body"`
|
||||||
MsgType MsgType `json:"msgtype"`
|
MsgType MsgType `json:"msgtype"`
|
||||||
RelatesTo RelatesTo `json:"m.relates_to,omitempty"`
|
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||||
Format MessageFormat `json:"format"`
|
Format MessageFormat `json:"format"`
|
||||||
NewContent NewContent `json:"m.new_content,omitempty"`
|
NewContent *NewContent `json:"m.new_content,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelatesTo holds information about relations to other message events
|
// RelatesTo holds information about relations to other message events
|
||||||
|
@ -53,7 +54,7 @@ type NewContent struct {
|
||||||
|
|
||||||
// SendNotification sends a notification to the specified user.
|
// SendNotification sends a notification to the specified user.
|
||||||
func (d *Dispatcher) SendNotification(a *model.Application, n *model.Notification) (eventId string, err error) {
|
func (d *Dispatcher) SendNotification(a *model.Application, n *model.Notification) (eventId string, err error) {
|
||||||
log.Printf("Sending notification to room %s.", a.MatrixID)
|
log.L.Printf("Sending notification to room %s.", a.MatrixID)
|
||||||
|
|
||||||
plainMessage := strings.TrimSpace(n.Message)
|
plainMessage := strings.TrimSpace(n.Message)
|
||||||
plainTitle := strings.TrimSpace(n.Title)
|
plainTitle := strings.TrimSpace(n.Title)
|
||||||
|
@ -77,7 +78,7 @@ func (d *Dispatcher) SendNotification(a *model.Application, n *model.Notificatio
|
||||||
|
|
||||||
// DeleteNotification sends a notification to the specified user that another notificaion is deleted
|
// DeleteNotification sends a notification to the specified user that another notificaion is deleted
|
||||||
func (d *Dispatcher) DeleteNotification(a *model.Application, n *model.DeleteNotification) error {
|
func (d *Dispatcher) DeleteNotification(a *model.Application, n *model.DeleteNotification) error {
|
||||||
log.Printf("Sending delete notification to room %s", a.MatrixID)
|
log.L.Printf("Sending delete notification to room %s", a.MatrixID)
|
||||||
var oldFormattedBody string
|
var oldFormattedBody string
|
||||||
var oldBody string
|
var oldBody string
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ func (d *Dispatcher) DeleteNotification(a *model.Application, n *model.DeleteNot
|
||||||
deleteMessage, err := d.getMessage(a, n.ID)
|
deleteMessage, err := d.getMessage(a, n.ID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.L.Println(err)
|
||||||
return pberrors.ErrorMessageNotFound
|
return pberrors.ErrorMessageNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +134,7 @@ func (d *Dispatcher) getFormattedMessage(n *model.Notification) string {
|
||||||
if ok {
|
if ok {
|
||||||
if contentTypeRaw, ok := optionsDisplay["contentType"]; ok {
|
if contentTypeRaw, ok := optionsDisplay["contentType"]; ok {
|
||||||
contentType := fmt.Sprintf("%v", contentTypeRaw)
|
contentType := fmt.Sprintf("%v", contentTypeRaw)
|
||||||
log.Printf("Message content type: %s", contentType)
|
log.L.Printf("Message content type: %s", contentType)
|
||||||
|
|
||||||
switch contentType {
|
switch contentType {
|
||||||
case "html", "text/html":
|
case "html", "text/html":
|
||||||
|
@ -212,15 +213,15 @@ func (d *Dispatcher) replaceMessage(a *model.Application, newBody, newFormattedB
|
||||||
Body: oldBody,
|
Body: oldBody,
|
||||||
FormattedBody: oldFormattedBody,
|
FormattedBody: oldFormattedBody,
|
||||||
MsgType: MsgTypeText,
|
MsgType: MsgTypeText,
|
||||||
NewContent: newMessage,
|
NewContent: &newMessage,
|
||||||
RelatesTo: replaceRelation,
|
RelatesTo: &replaceRelation,
|
||||||
Format: MessageFormatHTML,
|
Format: MessageFormatHTML,
|
||||||
}
|
}
|
||||||
|
|
||||||
sendEvent, err := d.mautrixClient.SendMessageEvent(mId.RoomID(a.MatrixID), event.EventMessage, &replaceEvent)
|
sendEvent, err := d.mautrixClient.SendMessageEvent(mId.RoomID(a.MatrixID), event.EventMessage, &replaceEvent)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.L.Println(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +253,7 @@ func (d *Dispatcher) respondToMessage(a *model.Application, body, formattedBody
|
||||||
notificationRelation := RelatesTo{
|
notificationRelation := RelatesTo{
|
||||||
InReplyTo: notificationReply,
|
InReplyTo: notificationReply,
|
||||||
}
|
}
|
||||||
notificationEvent.RelatesTo = notificationRelation
|
notificationEvent.RelatesTo = ¬ificationRelation
|
||||||
|
|
||||||
return d.mautrixClient.SendMessageEvent(mId.RoomID(a.MatrixID), event.EventMessage, ¬ificationEvent)
|
return d.mautrixClient.SendMessageEvent(mId.RoomID(a.MatrixID), event.EventMessage, ¬ificationEvent)
|
||||||
}
|
}
|
||||||
|
|
77
internal/log/ginlogrus.go
Normal file
77
internal/log/ginlogrus.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Source: https://github.com/toorop/gin-logrus
|
||||||
|
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GinLogger integrates logrus with gin
|
||||||
|
func GinLogger(logger logrus.FieldLogger, notLogged ...string) gin.HandlerFunc {
|
||||||
|
hostname, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
hostname = "unknow"
|
||||||
|
}
|
||||||
|
|
||||||
|
var skip map[string]struct{}
|
||||||
|
|
||||||
|
if length := len(notLogged); length > 0 {
|
||||||
|
skip = make(map[string]struct{}, length)
|
||||||
|
|
||||||
|
for _, p := range notLogged {
|
||||||
|
skip[p] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
path := c.Request.URL.Path
|
||||||
|
start := time.Now()
|
||||||
|
c.Next()
|
||||||
|
stop := time.Since(start)
|
||||||
|
latency := int(math.Ceil(float64(stop.Nanoseconds()) / 1000000.0))
|
||||||
|
statusCode := c.Writer.Status()
|
||||||
|
clientIP := c.ClientIP()
|
||||||
|
clientUserAgent := c.Request.UserAgent()
|
||||||
|
referer := c.Request.Referer()
|
||||||
|
dataLength := c.Writer.Size()
|
||||||
|
if dataLength < 0 {
|
||||||
|
dataLength = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := skip[path]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := logger.WithFields(logrus.Fields{
|
||||||
|
"hostname": hostname,
|
||||||
|
"statusCode": statusCode,
|
||||||
|
"latency": latency,
|
||||||
|
"clientIP": clientIP,
|
||||||
|
"method": c.Request.Method,
|
||||||
|
"path": path,
|
||||||
|
"referer": referer,
|
||||||
|
"dataLength": dataLength,
|
||||||
|
"userAgent": clientUserAgent,
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(c.Errors) > 0 {
|
||||||
|
entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
|
||||||
|
} else {
|
||||||
|
msg := fmt.Sprintf("%s [%d] %s %s", clientIP, statusCode, c.Request.Method, path)
|
||||||
|
if statusCode >= http.StatusInternalServerError {
|
||||||
|
entry.Error(msg)
|
||||||
|
} else if statusCode >= http.StatusBadRequest {
|
||||||
|
entry.Warn(msg)
|
||||||
|
} else {
|
||||||
|
entry.Info(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
internal/log/log.go
Normal file
22
internal/log/log.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var L *log.Logger
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
L = log.New()
|
||||||
|
L.SetOutput(os.Stderr)
|
||||||
|
L.SetLevel(log.InfoLevel)
|
||||||
|
L.SetFormatter(&log.TextFormatter{
|
||||||
|
DisableTimestamp: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDebug() {
|
||||||
|
L.SetLevel(log.DebugLevel)
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/authentication/credentials"
|
"github.com/pushbits/server/internal/authentication/credentials"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User holds information like the name, the secret, and the applications of a user.
|
// User holds information like the name, the secret, and the applications of a user.
|
||||||
|
@ -37,7 +36,7 @@ type CreateUser struct {
|
||||||
|
|
||||||
// NewUser creates a new user.
|
// NewUser creates a new user.
|
||||||
func NewUser(cm *credentials.Manager, name, password string, isAdmin bool, matrixID string) (*User, error) {
|
func NewUser(cm *credentials.Manager, name, password string, isAdmin bool, matrixID string) (*User, error) {
|
||||||
log.Printf("Creating user %s.", name)
|
log.L.Printf("Creating user %s.", name)
|
||||||
|
|
||||||
passwordHash, err := cm.CreatePasswordHash(password)
|
passwordHash, err := cm.CreatePasswordHash(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"github.com/gin-contrib/location"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/api"
|
"github.com/pushbits/server/internal/api"
|
||||||
"github.com/pushbits/server/internal/api/alertmanager"
|
"github.com/pushbits/server/internal/api/alertmanager"
|
||||||
|
@ -10,14 +11,12 @@ import (
|
||||||
"github.com/pushbits/server/internal/configuration"
|
"github.com/pushbits/server/internal/configuration"
|
||||||
"github.com/pushbits/server/internal/database"
|
"github.com/pushbits/server/internal/database"
|
||||||
"github.com/pushbits/server/internal/dispatcher"
|
"github.com/pushbits/server/internal/dispatcher"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
"github.com/gin-contrib/location"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a Gin engine and setup all routes.
|
// Create a Gin engine and setup all routes.
|
||||||
func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *dispatcher.Dispatcher, alertmanagerConfig *configuration.Alertmanager) *gin.Engine {
|
func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *dispatcher.Dispatcher, alertmanagerConfig *configuration.Alertmanager) *gin.Engine {
|
||||||
log.Println("Setting up HTTP routes.")
|
log.L.Println("Setting up HTTP routes.")
|
||||||
|
|
||||||
if !debug {
|
if !debug {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
@ -34,7 +33,8 @@ func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *disp
|
||||||
MessageAnnotation: alertmanagerConfig.AnnotationMessage,
|
MessageAnnotation: alertmanagerConfig.AnnotationMessage,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.New()
|
||||||
|
r.Use(log.GinLogger(log.L), gin.Recovery())
|
||||||
|
|
||||||
r.Use(location.Default())
|
r.Use(location.Default())
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,17 @@ package mockups
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/configuration"
|
"github.com/pushbits/server/internal/configuration"
|
||||||
|
"github.com/pushbits/server/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadConfig copies the given filename to the current folder and parses it as a config file. RemoveFile indicates whether to remove the copied file or not
|
// ReadConfig copies the given filename to the current folder and parses it as a config file. RemoveFile indicates whether to remove the copied file or not
|
||||||
func ReadConfig(filename string, removeFile bool) (config *configuration.Configuration, err error) {
|
func ReadConfig(filename string, removeFile bool) (config *configuration.Configuration, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
log.Println(r)
|
log.L.Println(r)
|
||||||
err = errors.New("paniced while reading config")
|
err = errors.New("paniced while reading config")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
Loading…
Add table
Reference in a new issue