merge dev.rievo.net/sst/domainCheck into discordBots
This commit is contained in:
parent
4dfeebf561
commit
c0f39ba894
7 changed files with 484 additions and 1 deletions
|
@ -53,4 +53,23 @@ dealsbot:
|
||||||
stage: build
|
stage: build
|
||||||
variables:
|
variables:
|
||||||
GO_CMD: dealsbot
|
GO_CMD: dealsbot
|
||||||
<<: *docker_build
|
<<: *docker_build
|
||||||
|
|
||||||
|
domaincheckbot:
|
||||||
|
stage: build
|
||||||
|
variables:
|
||||||
|
GO_CMD: domaincheckbot
|
||||||
|
<<: *docker_build
|
||||||
|
|
||||||
|
pages:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- mkdir public
|
||||||
|
- cp cmd/domaincheckbot/config/domains.json public/
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- public
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH
|
||||||
|
changes:
|
||||||
|
- cmd/domaincheckbot/config/domains.json
|
78
cmd/domaincheckadd/main.go
Normal file
78
cmd/domaincheckadd/main.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/config"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.Println("add domains to domains.json")
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
|
||||||
|
var newDomains []string
|
||||||
|
|
||||||
|
fmt.Print("domains: ")
|
||||||
|
if scanner.Scan() {
|
||||||
|
|
||||||
|
input := scanner.Text()
|
||||||
|
|
||||||
|
values := strings.Split(input, ",")
|
||||||
|
|
||||||
|
// trim space
|
||||||
|
for i := range values {
|
||||||
|
values[i] = strings.TrimSpace(values[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove empty
|
||||||
|
values = removeEmpty(values)
|
||||||
|
|
||||||
|
// sort
|
||||||
|
sort.SliceStable(values, func(i, j int) bool {
|
||||||
|
return values[i] < values[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
newDomains = values
|
||||||
|
}
|
||||||
|
log.Printf("domains to add: %v\n", newDomains)
|
||||||
|
|
||||||
|
fmt.Print("add to domains.json? [y|N]: ")
|
||||||
|
if scanner.Scan() {
|
||||||
|
input := scanner.Text()
|
||||||
|
if input == "y" || input == "Y" {
|
||||||
|
err := storeDomains(newDomains)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed storing domains.json")
|
||||||
|
}
|
||||||
|
fmt.Println("domains.json updated")
|
||||||
|
} else {
|
||||||
|
fmt.Println("canceled!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeDomains(domains []string) error {
|
||||||
|
for _, domain := range domains {
|
||||||
|
config.AddDomain(domain)
|
||||||
|
}
|
||||||
|
file, _ := json.MarshalIndent(config.Domains, "", " ")
|
||||||
|
err := os.WriteFile("./cmd/domaincheckbot/config/domain.json", file, 0644)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeEmpty(sliceList []string) []string {
|
||||||
|
var list []string
|
||||||
|
for _, str := range sliceList {
|
||||||
|
if str != "" {
|
||||||
|
list = append(list, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
40
cmd/domaincheckbot/config/domain.go
Normal file
40
cmd/domaincheckbot/config/domain.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/disgoorg/log"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed domain.json
|
||||||
|
var domainsFiles []byte
|
||||||
|
|
||||||
|
var Domains []string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
err := json.Unmarshal(domainsFiles, &Domains)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddDomain(domain string) {
|
||||||
|
domains := append(Domains, domain)
|
||||||
|
sort.SliceStable(domains, func(i, j int) bool {
|
||||||
|
return domains[i] < domains[j]
|
||||||
|
})
|
||||||
|
Domains = removeDuplicate(domains)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDuplicate[T string](sliceList []T) []T {
|
||||||
|
allKeys := make(map[T]bool)
|
||||||
|
var list []T
|
||||||
|
for _, item := range sliceList {
|
||||||
|
if _, value := allKeys[item]; !value {
|
||||||
|
allKeys[item] = true
|
||||||
|
list = append(list, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
105
cmd/domaincheckbot/config/domain.json
Normal file
105
cmd/domaincheckbot/config/domain.json
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
[
|
||||||
|
"1488.ch",
|
||||||
|
"ascii.tools",
|
||||||
|
"astonish.ch",
|
||||||
|
"astonishing.ch",
|
||||||
|
"attribution.ch",
|
||||||
|
"blizan.ch",
|
||||||
|
"buehnenbande.ch",
|
||||||
|
"ccc.ch",
|
||||||
|
"cori.us",
|
||||||
|
"dropdrop.dev",
|
||||||
|
"dropdrop.fun",
|
||||||
|
"dropdrop.pro",
|
||||||
|
"dropdrop.quest",
|
||||||
|
"dropdrop.wiki",
|
||||||
|
"example.com",
|
||||||
|
"familie.st",
|
||||||
|
"family.st",
|
||||||
|
"felizian.ch",
|
||||||
|
"felizian.st",
|
||||||
|
"fst.ch",
|
||||||
|
"g8.co",
|
||||||
|
"g8.com",
|
||||||
|
"g8.io",
|
||||||
|
"g8.is",
|
||||||
|
"g8.net",
|
||||||
|
"g8.nz",
|
||||||
|
"g8.re",
|
||||||
|
"gr8.click",
|
||||||
|
"gwydi.me",
|
||||||
|
"incline.ch",
|
||||||
|
"mojang.studio",
|
||||||
|
"nilu.ch",
|
||||||
|
"nqa.ch",
|
||||||
|
"phynecs.com",
|
||||||
|
"poisoned.app",
|
||||||
|
"poisonedapple.ch",
|
||||||
|
"rievo.app",
|
||||||
|
"rievo.cc",
|
||||||
|
"rievo.ch",
|
||||||
|
"rievo.co",
|
||||||
|
"rievo.co.uk",
|
||||||
|
"rievo.com",
|
||||||
|
"rievo.cz",
|
||||||
|
"rievo.de",
|
||||||
|
"rievo.dev",
|
||||||
|
"rievo.eu",
|
||||||
|
"rievo.eu.org",
|
||||||
|
"rievo.group",
|
||||||
|
"rievo.host",
|
||||||
|
"rievo.info",
|
||||||
|
"rievo.io",
|
||||||
|
"rievo.mx",
|
||||||
|
"rievo.net",
|
||||||
|
"rievo.org",
|
||||||
|
"rievo.page",
|
||||||
|
"rievo.swiss",
|
||||||
|
"rievo.systems",
|
||||||
|
"rievo.us",
|
||||||
|
"rievo.xyz",
|
||||||
|
"rv.gy",
|
||||||
|
"rvo.co",
|
||||||
|
"rvo.com",
|
||||||
|
"rvo.net",
|
||||||
|
"rvo.one",
|
||||||
|
"rvo.re",
|
||||||
|
"schuer.ch",
|
||||||
|
"schuerch.ch",
|
||||||
|
"schuerch.co",
|
||||||
|
"schuerch.com",
|
||||||
|
"schuerch.dev",
|
||||||
|
"schuerch.id",
|
||||||
|
"schuerch.net",
|
||||||
|
"schuerch.xyz",
|
||||||
|
"schur.ch",
|
||||||
|
"schurch.ch",
|
||||||
|
"schurch.com",
|
||||||
|
"schurch.dev",
|
||||||
|
"schurch.net",
|
||||||
|
"schwabe.ch",
|
||||||
|
"scrib.li",
|
||||||
|
"seraphimstrub.com",
|
||||||
|
"signage.ch",
|
||||||
|
"sos-esport.com",
|
||||||
|
"sos-esports.com",
|
||||||
|
"sst.ch",
|
||||||
|
"sst.place",
|
||||||
|
"strub.cc",
|
||||||
|
"strub.ch",
|
||||||
|
"strub.co",
|
||||||
|
"strub.com",
|
||||||
|
"strub.consulting",
|
||||||
|
"strub.info",
|
||||||
|
"strub.net",
|
||||||
|
"strub.one",
|
||||||
|
"strub.org",
|
||||||
|
"strub.st",
|
||||||
|
"strub.swiss",
|
||||||
|
"strub.xyz",
|
||||||
|
"swizer.land",
|
||||||
|
"thehat.ch",
|
||||||
|
"unlogis.ch",
|
||||||
|
"xii.st",
|
||||||
|
"xn--schrch-5ya.ch"
|
||||||
|
]
|
35
cmd/domaincheckbot/dns/domain.go
Normal file
35
cmd/domaincheckbot/dns/domain.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/repository"
|
||||||
|
"net"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CheckDomain(domain string) repository.Domain {
|
||||||
|
nameservers, err := net.LookupNS(domain)
|
||||||
|
|
||||||
|
if len(nameservers) > 0 && err == nil {
|
||||||
|
return repository.Domain{
|
||||||
|
Name: domain,
|
||||||
|
NS: nsToArray(nameservers),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return repository.Domain{
|
||||||
|
Name: domain,
|
||||||
|
NS: []string{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nsToArray(nameservers []*net.NS) []string {
|
||||||
|
var nsArray []string
|
||||||
|
for _, nameserver := range nameservers {
|
||||||
|
nsArray = append(nsArray, nameserver.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.SliceStable(nsArray, func(i, j int) bool {
|
||||||
|
return nsArray[i] < nsArray[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
return nsArray
|
||||||
|
}
|
98
cmd/domaincheckbot/main.go
Normal file
98
cmd/domaincheckbot/main.go
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/dgraph-io/badger/v4"
|
||||||
|
"github.com/disgoorg/disgo"
|
||||||
|
"github.com/disgoorg/disgo/discord"
|
||||||
|
"github.com/disgoorg/disgo/rest"
|
||||||
|
"github.com/disgoorg/disgo/webhook"
|
||||||
|
"github.com/disgoorg/log"
|
||||||
|
"github.com/disgoorg/snowflake/v2"
|
||||||
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/config"
|
||||||
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/dns"
|
||||||
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/repository"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"reflect"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
webhookID = snowflake.GetEnv("webhook_id")
|
||||||
|
webhookToken = os.Getenv("webhook_token")
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: clear db from domains removed from json
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetLevel(log.LevelInfo)
|
||||||
|
log.Info("starting domainCheck...")
|
||||||
|
log.Info("disgo version: ", disgo.Version)
|
||||||
|
|
||||||
|
client := webhook.New(webhookID, webhookToken)
|
||||||
|
defer client.Close(context.TODO())
|
||||||
|
|
||||||
|
repo := repository.InitDb()
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
ticker := time.NewTicker(10 * time.Minute)
|
||||||
|
tickerGC := time.NewTicker(15 * time.Minute)
|
||||||
|
quit := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
for _, d := range config.Domains {
|
||||||
|
domain := dns.CheckDomain(d)
|
||||||
|
retrievedDomain, _ := repo.GetValue(d)
|
||||||
|
if reflect.DeepEqual(domain, retrievedDomain) {
|
||||||
|
log.Debugf(" %v: did not change", d)
|
||||||
|
} else {
|
||||||
|
log.Infof("!%v: changed", d)
|
||||||
|
go sendWebhook(client, domain, retrievedDomain)
|
||||||
|
repo.SetValue(domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-tickerGC.C:
|
||||||
|
err := repo.RunGC()
|
||||||
|
if err != nil && !errors.Is(err, badger.ErrNoRewrite) {
|
||||||
|
log.Errorf("error with GC: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Debug("GC successful")
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-quit:
|
||||||
|
ticker.Stop()
|
||||||
|
tickerGC.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Infof("domainCheck is now running. Press CTRL-C to exit.")
|
||||||
|
s := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||||
|
<-s
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendWebhook(client webhook.Client, domain repository.Domain, oldDomain repository.Domain) {
|
||||||
|
var status string
|
||||||
|
|
||||||
|
status = fmt.Sprintf("```md\n# %v", domain.Name)
|
||||||
|
status = fmt.Sprintf("%v\n - %v", status, oldDomain.NS)
|
||||||
|
status = fmt.Sprintf("%v\n + %v", status, domain.NS)
|
||||||
|
status = fmt.Sprintf("%v```\n", status)
|
||||||
|
|
||||||
|
if _, err := client.CreateMessage(discord.NewWebhookMessageCreateBuilder().
|
||||||
|
SetContent(status).Build(),
|
||||||
|
rest.WithDelay(2*time.Second),
|
||||||
|
); err != nil {
|
||||||
|
log.Errorf("error sending message %v", err.Error())
|
||||||
|
}
|
||||||
|
}
|
108
cmd/domaincheckbot/repository/repository.go
Normal file
108
cmd/domaincheckbot/repository/repository.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/dgraph-io/badger/v4"
|
||||||
|
"github.com/disgoorg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Domain struct {
|
||||||
|
Name string
|
||||||
|
NS []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
GetAll() ([]Domain, error)
|
||||||
|
GetValue(domainName string) Domain
|
||||||
|
SetValue(domain Domain) error
|
||||||
|
DeleteValue(domainName string) error
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainRepository struct {
|
||||||
|
db *badger.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitDb() *DomainRepository {
|
||||||
|
opts := badger.DefaultOptions("./badger")
|
||||||
|
opts.Logger = nil
|
||||||
|
db, err := badger.Open(opts)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return &DomainRepository{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainRepository) Close() error {
|
||||||
|
return d.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainRepository) RunGC() error {
|
||||||
|
return d.db.RunValueLogGC(0.7)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainRepository) GetAll() ([]Domain, error) {
|
||||||
|
var domains []Domain
|
||||||
|
err := d.db.View(func(txn *badger.Txn) error {
|
||||||
|
opts := badger.DefaultIteratorOptions
|
||||||
|
opts.PrefetchSize = 10
|
||||||
|
it := txn.NewIterator(opts)
|
||||||
|
defer it.Close()
|
||||||
|
for it.Rewind(); it.Valid(); it.Next() {
|
||||||
|
item := it.Item()
|
||||||
|
err := item.Value(func(val []byte) error {
|
||||||
|
retrievedDomain := Domain{}
|
||||||
|
err := json.Unmarshal(val, &retrievedDomain)
|
||||||
|
domains = append(domains, retrievedDomain)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return domains, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainRepository) GetValue(domainName string) (Domain, error) {
|
||||||
|
retrievedDomain := Domain{}
|
||||||
|
err := d.db.View(func(txn *badger.Txn) error {
|
||||||
|
item, err := txn.Get([]byte(domainName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = item.Value(func(val []byte) error {
|
||||||
|
err = json.Unmarshal(val, &retrievedDomain)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return Domain{}, err
|
||||||
|
}
|
||||||
|
return retrievedDomain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainRepository) SetValue(domain Domain) error {
|
||||||
|
jsonBytes, err := json.Marshal(domain)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.db.Update(func(txn *badger.Txn) error {
|
||||||
|
err := txn.Set([]byte(domain.Name), jsonBytes)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainRepository) DeleteValue(domainName string) error {
|
||||||
|
err := d.db.Update(func(txn *badger.Txn) error {
|
||||||
|
err := txn.Delete([]byte(domainName))
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
Loading…
Reference in a new issue