mirror of
https://github.com/pushbits/server.git
synced 2025-06-07 13:11:59 +02:00
Merge branch 'main' into #24-switch-to-mautrix
This commit is contained in:
commit
dc6c76747f
22 changed files with 777 additions and 62 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
layout_poetry
|
3
.github/workflows/documentation.yml
vendored
3
.github/workflows/documentation.yml
vendored
|
@ -31,6 +31,9 @@ jobs:
|
|||
with:
|
||||
go-version: 1.16
|
||||
|
||||
- name: Install Poetry
|
||||
run: curl -sSL https://install.python-poetry.org | python3 -
|
||||
|
||||
- name: Install dependencies
|
||||
run: make setup
|
||||
|
||||
|
|
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
|
@ -1,4 +1,5 @@
|
|||
name: Main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
|
@ -7,6 +8,7 @@ on:
|
|||
- '**'
|
||||
- '!v[0-9]+.[0-9]+.[0-9]+'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test_build:
|
||||
name: Test and build
|
||||
|
@ -14,11 +16,19 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Export GOBIN
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
|
||||
- name: Install Poetry
|
||||
run: curl -sSL https://install.python-poetry.org | python3 -
|
||||
|
||||
- name: Install dependencies
|
||||
run: make setup
|
||||
|
||||
- name: Run tests
|
||||
run: make test
|
||||
run: |
|
||||
source $(poetry env info --path)/bin/activate
|
||||
make test
|
||||
|
|
16
.github/workflows/publish.yml
vendored
16
.github/workflows/publish.yml
vendored
|
@ -25,11 +25,16 @@ jobs:
|
|||
with:
|
||||
go-version: 1.16
|
||||
|
||||
- name: Install Poetry
|
||||
run: curl -sSL https://install.python-poetry.org | python3 -
|
||||
|
||||
- name: Install dependencies
|
||||
run: make setup
|
||||
|
||||
- name: Run tests
|
||||
run: make test
|
||||
run: |
|
||||
source $(poetry env info --path)/bin/activate
|
||||
make test
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v1
|
||||
|
@ -53,3 +58,12 @@ jobs:
|
|||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
151
.gitignore
vendored
151
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
|||
out/
|
||||
*.db
|
||||
config.yml
|
||||
docs/
|
||||
|
||||
### Go
|
||||
# Binaries for programs and plugins
|
||||
|
@ -19,8 +20,154 @@ config.yml
|
|||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
### Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
### VisualStudioCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Build documentation
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
docs/
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "tests/semgrep-rules"]
|
||||
path = tests/semgrep-rules
|
||||
url = https://github.com/returntocorp/semgrep-rules
|
19
.goreleaser.yml
Normal file
19
.goreleaser.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
builds:
|
||||
- id: pushbits
|
||||
main: ./cmd/pushbits
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
- 386
|
||||
- arm
|
||||
- arm64
|
||||
|
||||
checksum:
|
||||
algorithm: sha256
|
||||
|
||||
archives:
|
||||
- id: pushbits
|
||||
builds:
|
||||
- pushbits
|
||||
format: tar.gz
|
32
Makefile
32
Makefile
|
@ -1,23 +1,45 @@
|
|||
# References:
|
||||
# [1] Needed so the Go files of semgrep-rules do not interfere with static analysis
|
||||
|
||||
DOCS_DIR := ./docs
|
||||
OUT_DIR := ./out
|
||||
TESTS_DIR := ./tests
|
||||
|
||||
SEMGREP_MODFILE := $(TESTS_DIR)/semgrep-rules/go.mod
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
mkdir -p ./out
|
||||
go build -ldflags="-w -s" -o ./out/pushbits ./cmd/pushbits
|
||||
mkdir -p $(OUT_DIR)
|
||||
go build -ldflags="-w -s" -o $(OUT_DIR)/pushbits ./cmd/pushbits
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(DOCS_DIR)
|
||||
rm -rf $(OUT_DIR)
|
||||
rm -rf $(SEMGREP_MODFILE)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
stdout=$$(gofmt -l . 2>&1); if [ "$$stdout" ]; then exit 1; fi
|
||||
touch $(SEMGREP_MODFILE) # See [1].
|
||||
go fmt ./...
|
||||
go vet ./...
|
||||
gocyclo -over 10 $(shell find . -iname '*.go' -type f)
|
||||
gocyclo -over 10 $(shell find . -type f \( -iname '*.go' ! -path "./tests/semgrep-rules/*" \))
|
||||
staticcheck ./...
|
||||
go test -v -cover ./...
|
||||
gosec -exclude-dir=tests ./...
|
||||
semgrep --lang=go --config=tests/semgrep-rules/go --metrics=off
|
||||
rm -rf $(SEMGREP_MODFILE) # See [1].
|
||||
@printf '\n%s\n' "> Test successful"
|
||||
|
||||
.PHONY: setup
|
||||
setup:
|
||||
git submodule update --init --recursive
|
||||
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
poetry install
|
||||
|
||||
.PHONY: swag
|
||||
swag:
|
||||
swag init --parseDependency=true -d . -g cmd/pushbits/main.go
|
||||
swag init --parseDependency=true --exclude $(TESTS_DIR) -g cmd/pushbits/main.go
|
||||
|
|
54
README.md
54
README.md
|
@ -9,9 +9,7 @@
|
|||
|
||||
<div align="center">
|
||||
<h1>PushBits</h1>
|
||||
<h4 align="center">
|
||||
Receive your important notifications immediately, over <a href="https://matrix.org/">Matrix</a>.
|
||||
</h4>
|
||||
<p align="center"><b>Receive your important notifications immediately, over <a href="https://matrix.org/">Matrix</a>.</b></p>
|
||||
<p>PushBits enables you to send push notifications via a simple web API, and delivers them to your users.</p>
|
||||
</div>
|
||||
|
||||
|
@ -31,21 +29,7 @@ It enables you to send notifications via a simple web API, and delivers them to
|
|||
This is similar to what [Pushover](https://pushover.net/) and [Gotify](https://gotify.net/) offer, but it does not require an additional app.
|
||||
|
||||
The vision is to have compatibility with Gotify on the sending side, while on the receiving side an established service is used.
|
||||
This has the advantages that
|
||||
- sending plugins written for Gotify (like those for [Watchtower](https://containrrr.dev/watchtower/) and [Jellyfin](https://jellyfin.org/)) as well as
|
||||
- receiving clients written for Matrix
|
||||
can be reused.
|
||||
|
||||
### Why Matrix instead of X?
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
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.
|
||||
This has the advantages that we need to maintain neither plugins (like those for [Watchtower](https://containrrr.dev/watchtower/) and [Jellyfin](https://jellyfin.org/)) nor clients.
|
||||
|
||||
## 🤘 Features
|
||||
|
||||
|
@ -57,18 +41,38 @@ Still, if you haven't tried it yet, we'd encourage you to check it out.
|
|||
- [ ] Two-factor authentication, [issue](https://github.com/pushbits/server/issues/19)
|
||||
- [ ] Bi-directional key verification, [issue](https://github.com/pushbits/server/issues/20)
|
||||
|
||||
## 👮 Acknowledgments
|
||||
## 👮 License and Acknowledgments
|
||||
|
||||
The idea for this software and most parts of the initial source are heavily inspired by [Gotify](https://gotify.net/).
|
||||
Many thanks to [jmattheis](https://jmattheis.de/) for his well-structured code.
|
||||
Please refer to [the LICENSE file](LICENSE) to learn more about the license of this code.
|
||||
It applies only where not specified differently.
|
||||
|
||||
## 💻 Development
|
||||
The idea for this software was inspired by [Gotify](https://gotify.net/).
|
||||
|
||||
The source code is located on [GitHub](https://github.com/pushbits/server).
|
||||
You can retrieve it by checking out the repository as follows.
|
||||
## 💻 Development and Contributions
|
||||
|
||||
The source code is located [on GitHub](https://github.com/pushbits/server).
|
||||
You can retrieve it by checking out the repository as follows:
|
||||
```bash
|
||||
git clone https://github.com/pushbits/server.git
|
||||
```
|
||||
|
||||
[](https://starchart.cc/pushbits/server)
|
||||
:wrench: **Want to contribute?**
|
||||
Before moving forward, please refer to [our contribution guidelines](CONTRIBUTING.md).
|
||||
|
||||
:mailbox: **Found a security vulnerability?**
|
||||
Check [this document](SECURITY.md) for information on how you can bring it to our attention.
|
||||
|
||||
:star: **Like fancy graphs?** See [our stargazers over time](https://starchart.cc/pushbits/server).
|
||||
|
||||
## ❓ Frequently Asked Questions (FAQ)
|
||||
|
||||
### Why Matrix instead of X?
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
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.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Supported Versions
|
||||
|
||||
Only the latest version is supported.
|
||||
Because we are a small team, only the latest version is supported.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
|
|
@ -77,5 +77,8 @@ func main() {
|
|||
|
||||
engine := router.Create(c.Debug, cm, db, dp)
|
||||
|
||||
runner.Run(engine, c.HTTP.ListenAddress, c.HTTP.Port)
|
||||
err = runner.Run(engine, c.HTTP.ListenAddress, c.HTTP.Port)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,11 @@ func (h *ApplicationHandler) registerApplication(ctx *gin.Context, a *model.Appl
|
|||
}
|
||||
|
||||
a.MatrixID = channelID
|
||||
h.DB.UpdateApplication(a)
|
||||
|
||||
err = h.DB.UpdateApplication(a)
|
||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -55,7 +59,6 @@ func (h *ApplicationHandler) createApplication(ctx *gin.Context, u *model.User,
|
|||
|
||||
if err := h.registerApplication(ctx, &application, u); err != nil {
|
||||
err := h.DB.DeleteApplication(&application)
|
||||
|
||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||
log.Printf("Cannot delete application with ID %d.", application.ID)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pushbits/server/internal/authentication"
|
||||
|
@ -45,23 +44,17 @@ type NotificationHandler struct {
|
|||
// @Failure 500,404,403 ""
|
||||
// @Router /message [post]
|
||||
func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
||||
var notification model.Notification
|
||||
application := authentication.GetApplication(ctx)
|
||||
log.Printf("Sending notification for application %s.", application.Name)
|
||||
|
||||
var notification model.Notification
|
||||
if err := ctx.Bind(¬ification); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
application := authentication.GetApplication(ctx)
|
||||
log.Printf("Sending notification for application %s.", application.Name)
|
||||
|
||||
notification.ApplicationID = application.ID
|
||||
if strings.TrimSpace(notification.Title) == "" {
|
||||
notification.Title = application.Name
|
||||
}
|
||||
notification.Date = time.Now()
|
||||
notification.Sanitize(application)
|
||||
|
||||
messageID, err := h.DP.SendNotification(application, ¬ification)
|
||||
|
||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||
return
|
||||
}
|
||||
|
@ -86,8 +79,9 @@ func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
|||
// @Router /message/{message_id} [DELETE]
|
||||
func (h *NotificationHandler) DeleteNotification(ctx *gin.Context) {
|
||||
application := authentication.GetApplication(ctx)
|
||||
id, err := getMessageID(ctx)
|
||||
log.Printf("Deleting notification for application %s.", application.Name)
|
||||
|
||||
id, err := getMessageID(ctx)
|
||||
if success := successOrAbort(ctx, http.StatusUnprocessableEntity, err); !success {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ func (h *UserHandler) deleteApplications(ctx *gin.Context, u *model.User) error
|
|||
}
|
||||
|
||||
for _, application := range applications {
|
||||
application := application // See https://stackoverflow.com/a/68247837
|
||||
|
||||
if err := h.AH.deleteApplication(ctx, &application, u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -59,6 +61,8 @@ func (h *UserHandler) updateChannels(ctx *gin.Context, u *model.User, matrixID s
|
|||
}
|
||||
|
||||
for _, application := range applications {
|
||||
application := application // See https://stackoverflow.com/a/68247837
|
||||
|
||||
err := h.DP.DeregisterApplication(&application, u)
|
||||
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||
return err
|
||||
|
@ -68,6 +72,8 @@ func (h *UserHandler) updateChannels(ctx *gin.Context, u *model.User, matrixID s
|
|||
u.MatrixID = matrixID
|
||||
|
||||
for _, application := range applications {
|
||||
application := application // See https://stackoverflow.com/a/68247837
|
||||
|
||||
err := h.AH.registerApplication(ctx, &application, u)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -169,10 +175,10 @@ func (h *UserHandler) GetUsers(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
var externalUsers []*model.ExternalUser
|
||||
externalUsers := make([]*model.ExternalUser, len(users))
|
||||
|
||||
for _, user := range users {
|
||||
externalUsers = append(externalUsers, user.IntoExternalUser())
|
||||
for i, user := range users {
|
||||
externalUsers[i] = user.IntoExternalUser()
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, &externalUsers)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha1" //#nosec G505 -- False positive, see the use below.
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
@ -21,7 +21,8 @@ func IsPasswordPwned(password string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
hash := sha1.Sum([]byte(password))
|
||||
// nosemgrep: tests.semgrep-rules.go.lang.security.audit.crypto.insecure-module-used, tests.semgrep-rules.go.lang.security.audit.crypto.use-of-sha1
|
||||
hash := sha1.Sum([]byte(password)) //#nosec G401 -- False positive, only the first 5 bytes are transmitted.
|
||||
hashStr := fmt.Sprintf("%X", hash)
|
||||
lookup := hashStr[0:5]
|
||||
match := hashStr[5:]
|
||||
|
|
|
@ -24,8 +24,11 @@ type Database struct {
|
|||
}
|
||||
|
||||
func createFileDir(file string) {
|
||||
if _, err := os.Stat(filepath.Dir(file)); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0775); err != nil {
|
||||
dir := filepath.Dir(file)
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
// nosemgrep: tests.semgrep-rules.go.lang.correctness.permissions.incorrect-default-permission
|
||||
if err := os.MkdirAll(dir, 0750); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -67,14 +70,20 @@ func Create(cm *credentials.Manager, dialect, connection string) (*Database, err
|
|||
sql.SetConnMaxLifetime(9 * time.Minute)
|
||||
}
|
||||
|
||||
db.AutoMigrate(&model.User{}, &model.Application{})
|
||||
err = db.AutoMigrate(&model.User{}, &model.Application{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Database{gormdb: db, sqldb: sql, credentialsManager: cm}, nil
|
||||
}
|
||||
|
||||
// Close closes the database connection.
|
||||
func (d *Database) Close() {
|
||||
d.sqldb.Close()
|
||||
err := d.sqldb.Close()
|
||||
if err != nil {
|
||||
log.Printf("Error while closing database: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Populate fills the database with initial information like the admin user.
|
||||
|
@ -111,12 +120,16 @@ func (d *Database) RepairChannels(dp Dispatcher) error {
|
|||
}
|
||||
|
||||
for _, user := range users {
|
||||
user := user // See https://stackoverflow.com/a/68247837
|
||||
|
||||
applications, err := d.GetApplications(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, application := range applications {
|
||||
application := application // See https://stackoverflow.com/a/68247837
|
||||
|
||||
if err := dp.UpdateApplication(&application); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -41,7 +41,11 @@ func Create(homeserver, username, password string, formatting configuration.Form
|
|||
func (d *Dispatcher) Close() {
|
||||
log.Printf("Logging out.")
|
||||
|
||||
d.mautrixClient.Logout()
|
||||
_, err := d.mautrixClient.Logout()
|
||||
if err != nil {
|
||||
log.Printf("Error while logging out: %s", err)
|
||||
}
|
||||
|
||||
d.mautrixClient.ClearCredentials()
|
||||
|
||||
log.Printf("Successfully logged out.")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -16,6 +17,17 @@ type Notification struct {
|
|||
Date time.Time `json:"date"`
|
||||
}
|
||||
|
||||
// Sanitize sets explicit defaults for a notification.
|
||||
func (n *Notification) Sanitize(application *Application) {
|
||||
n.ID = ""
|
||||
n.UrlEncodedID = ""
|
||||
n.ApplicationID = application.ID
|
||||
if strings.TrimSpace(n.Title) == "" {
|
||||
n.Title = application.Name
|
||||
}
|
||||
n.Date = time.Now()
|
||||
}
|
||||
|
||||
// DeleteNotification holds information like the message ID of a deletion notification.
|
||||
type DeleteNotification struct {
|
||||
ID string `json:"id" form:"id"`
|
||||
|
|
|
@ -7,6 +7,11 @@ import (
|
|||
)
|
||||
|
||||
// Run starts the Gin engine.
|
||||
func Run(engine *gin.Engine, address string, port int) {
|
||||
engine.Run(fmt.Sprintf("%s:%d", address, port))
|
||||
func Run(engine *gin.Engine, address string, port int) error {
|
||||
err := engine.Run(fmt.Sprintf("%s:%d", address, port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
439
poetry.lock
generated
Normal file
439
poetry.lock
generated
Normal file
|
@ -0,0 +1,439 @@
|
|||
[[package]]
|
||||
name = "attrs"
|
||||
version = "21.4.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
|
||||
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
|
||||
|
||||
[[package]]
|
||||
name = "bracex"
|
||||
version = "2.2.1"
|
||||
description = "Bash style brace expander."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2021.10.8"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "2.0.12"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5.0"
|
||||
|
||||
[package.extras]
|
||||
unicode_backport = ["unicodedata2"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.0.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "click-option-group"
|
||||
version = "0.5.3"
|
||||
description = "Option groups missing in Click"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4"
|
||||
|
||||
[package.dependencies]
|
||||
Click = ">=7.0,<9"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=2.3,<3)", "pallets-sphinx-themes", "m2r"]
|
||||
tests = ["coverage (<6)", "pytest", "pytest-cov", "coveralls"]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.3"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "4.11.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
perf = ["ipython"]
|
||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-resources"
|
||||
version = "5.4.0"
|
||||
description = "Read resources from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||
|
||||
[[package]]
|
||||
name = "jsonschema"
|
||||
version = "4.4.0"
|
||||
description = "An implementation of JSON Schema validation for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=17.4.0"
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
|
||||
pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
|
||||
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
|
||||
format_nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.3"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "peewee"
|
||||
version = "3.14.8"
|
||||
description = "a little orm"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.7"
|
||||
description = "Python parsing module"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pyrsistent"
|
||||
version = "0.18.1"
|
||||
description = "Persistent/Functional/Immutable data structures"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.27.1"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
|
||||
idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruamel.yaml"
|
||||
version = "0.17.21"
|
||||
description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
|
||||
[package.dependencies]
|
||||
"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["ryd"]
|
||||
jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruamel.yaml.clib"
|
||||
version = "0.2.6"
|
||||
description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "semgrep"
|
||||
version = "0.82.0"
|
||||
description = "Lightweight static analysis for many languages. Find bug variants with patterns that look like source code."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=19.3.0"
|
||||
click = ">=8.0.1"
|
||||
click-option-group = ">=0.5.3"
|
||||
colorama = ">=0.4.3"
|
||||
jsonschema = ">=3.2.0,<5"
|
||||
packaging = ">=20.4"
|
||||
peewee = ">=3.14.4,<3.15.0"
|
||||
requests = ">=2.22.0"
|
||||
"ruamel.yaml" = ">=0.16.0,<0.18"
|
||||
tqdm = ">=4.46.1"
|
||||
wcmatch = "8.3"
|
||||
|
||||
[[package]]
|
||||
name = "tqdm"
|
||||
version = "4.62.3"
|
||||
description = "Fast, Extensible Progress Meter"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[package.extras]
|
||||
dev = ["py-make (>=0.1.0)", "twine", "wheel"]
|
||||
notebook = ["ipywidgets (>=6)"]
|
||||
telegram = ["requests"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.1.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.6+"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.8"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcmatch"
|
||||
version = "8.3"
|
||||
description = "Wildcard/glob file name matcher."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
bracex = ">=2.1.1"
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.7.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "792ec3aa3a1641a70a6cd82c2399211c85c8a5cad5522f260c86ef407f8482ce"
|
||||
|
||||
[metadata.files]
|
||||
attrs = [
|
||||
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
|
||||
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
|
||||
]
|
||||
bracex = [
|
||||
{file = "bracex-2.2.1-py3-none-any.whl", hash = "sha256:096c4b788bf492f7af4e90ef8b5bcbfb99759ae3415ea1b83c9d29a5ed8f9a94"},
|
||||
{file = "bracex-2.2.1.tar.gz", hash = "sha256:1c8d1296e00ad9a91030ccb4c291f9e4dc7c054f12c707ba3c5ff3e9a81bcd21"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
|
||||
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
|
||||
{file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
|
||||
{file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
|
||||
]
|
||||
click-option-group = [
|
||||
{file = "click-option-group-0.5.3.tar.gz", hash = "sha256:a6e924f3c46b657feb5b72679f7e930f8e5b224b766ab35c91ae4019b4e0615e"},
|
||||
{file = "click_option_group-0.5.3-py3-none-any.whl", hash = "sha256:9653a2297357335d7325a1827e71ac1245d91c97d959346a7decabd4a52d5354"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||
]
|
||||
idna = [
|
||||
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-4.11.0-py3-none-any.whl", hash = "sha256:6affcdb3aec542dd98df8211e730bba6c5f2bec8288d47bacacde898f548c9ad"},
|
||||
{file = "importlib_metadata-4.11.0.tar.gz", hash = "sha256:9e5e553bbba1843cb4a00823014b907616be46ee503d2b9ba001d214a8da218f"},
|
||||
]
|
||||
importlib-resources = [
|
||||
{file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"},
|
||||
{file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"},
|
||||
]
|
||||
jsonschema = [
|
||||
{file = "jsonschema-4.4.0-py3-none-any.whl", hash = "sha256:77281a1f71684953ee8b3d488371b162419767973789272434bbc3f29d9c8823"},
|
||||
{file = "jsonschema-4.4.0.tar.gz", hash = "sha256:636694eb41b3535ed608fe04129f26542b59ed99808b4f688aa32dcf55317a83"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
peewee = [
|
||||
{file = "peewee-3.14.8.tar.gz", hash = "sha256:01bd7f734defb08d7a3346a0c0ca7011bc8d0d685934ec0e001b3371d522ec53"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
|
||||
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
|
||||
]
|
||||
pyrsistent = [
|
||||
{file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"},
|
||||
{file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"},
|
||||
{file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"},
|
||||
{file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"},
|
||||
{file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"},
|
||||
{file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"},
|
||||
{file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"},
|
||||
{file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"},
|
||||
{file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"},
|
||||
{file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"},
|
||||
{file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"},
|
||||
{file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"},
|
||||
{file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"},
|
||||
{file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"},
|
||||
{file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"},
|
||||
{file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"},
|
||||
{file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"},
|
||||
{file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"},
|
||||
{file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"},
|
||||
{file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"},
|
||||
{file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
|
||||
{file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
|
||||
]
|
||||
"ruamel.yaml" = [
|
||||
{file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"},
|
||||
{file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"},
|
||||
]
|
||||
"ruamel.yaml.clib" = [
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win32.whl", hash = "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win_amd64.whl", hash = "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win32.whl", hash = "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win_amd64.whl", hash = "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win32.whl", hash = "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win32.whl", hash = "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104"},
|
||||
{file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7"},
|
||||
{file = "ruamel.yaml.clib-0.2.6.tar.gz", hash = "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd"},
|
||||
]
|
||||
semgrep = [
|
||||
{file = "semgrep-0.82.0-cp37.cp38.cp39.py37.py38.py39-none-any.whl", hash = "sha256:1750f2b755ffc7db4690e6c5990e03e03729e6de4d4c4edf3f39435020244989"},
|
||||
{file = "semgrep-0.82.0-cp37.cp38.cp39.py37.py38.py39-none-macosx_10_14_x86_64.whl", hash = "sha256:037124db822a0c9235ea6cfbc637f06771ca2882d181dfdbd460c430bf51d7ec"},
|
||||
{file = "semgrep-0.82.0.tar.gz", hash = "sha256:aa6c57d08602ffde3bf36159c0325d6d72f70dc634cd237f30ff46f7d6b78be3"},
|
||||
]
|
||||
tqdm = [
|
||||
{file = "tqdm-4.62.3-py2.py3-none-any.whl", hash = "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c"},
|
||||
{file = "tqdm-4.62.3.tar.gz", hash = "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-4.1.0-py3-none-any.whl", hash = "sha256:c13180fbaa7cd97065a4915ceba012bdb31dc34743e63ddee16360161d358414"},
|
||||
{file = "typing_extensions-4.1.0.tar.gz", hash = "sha256:ba97c5143e5bb067b57793c726dd857b1671d4b02ced273ca0538e71ff009095"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
|
||||
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
|
||||
]
|
||||
wcmatch = [
|
||||
{file = "wcmatch-8.3-py3-none-any.whl", hash = "sha256:7141d2c85314253f16b38cb3d6cc0fb612918d407e1df3ccc2be7c86cc259c22"},
|
||||
{file = "wcmatch-8.3.tar.gz", hash = "sha256:371072912398af61d1e4e78609e18801c6faecd3cb36c54c82556a60abc965db"},
|
||||
]
|
||||
zipp = [
|
||||
{file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
|
||||
{file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
|
||||
]
|
11
pyproject.toml
Normal file
11
pyproject.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[tool.poetry]
|
||||
name = "pushbits"
|
||||
version = "0.0.0"
|
||||
description = ""
|
||||
authors = []
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
semgrep = "^0.82.0"
|
1
tests/semgrep-rules
Submodule
1
tests/semgrep-rules
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 46e040f844c2b1c40599c8d4f1cdf277b197329e
|
Loading…
Add table
Add a link
Reference in a new issue