[project] init
This commit is contained in:
commit
dfec6f5cdc
13 changed files with 294 additions and 0 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
!src
|
||||
!cmd
|
||||
!go.mod
|
||||
!go.sum
|
||||
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# env file
|
||||
.env
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FROM golang:1.22-alpine as builder
|
||||
|
||||
# build app
|
||||
WORKDIR /opt/serverchecker/src
|
||||
COPY . /opt/serverchecker/src
|
||||
|
||||
RUN go build -o /opt/serverchecker/serverchecker cmd/main.go
|
||||
RUN chmod a+x /opt/serverchecker/serverchecker
|
||||
|
||||
# target image
|
||||
FROM golang:1.22-alpine
|
||||
RUN mkdir -p /opt/serverchecker
|
||||
|
||||
COPY --from=builder /opt/serverchecker/serverchecker /opt/serverchecker/serverchecker
|
||||
RUN crontab -l | { cat; echo "0 * * * * /opt/serverchecker/serverchecker"; } | crontab -
|
||||
|
||||
|
||||
CMD ["crond", "-f", "-l", "2"]
|
||||
0
Readme.md
Normal file
0
Readme.md
Normal file
15
cmd/main.go
Normal file
15
cmd/main.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"git.domandoman.xyz/doman/serverchecker/src"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config, err := src.GetConfig()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
src.RunCheck(config)
|
||||
}
|
||||
9
docker-compose.yaml
Normal file
9
docker-compose.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
services:
|
||||
app:
|
||||
image: serverchecker
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- .env
|
||||
4
env.template
Normal file
4
env.template
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
DISCORD_TOKEN=""
|
||||
DISCORD_CHANNEL_ID=""
|
||||
CHECK_DOMAINS="[\"google.com\"]"
|
||||
CHECK_NOTIFY_EXPIRATION_DAYS=7
|
||||
15
go.mod
Normal file
15
go.mod
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
module git.domandoman.xyz/doman/serverchecker
|
||||
|
||||
go 1.22.5
|
||||
|
||||
require (
|
||||
git.domandoman.xyz/doman/certchecker v0.0.2
|
||||
github.com/bwmarrin/discordgo v0.28.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||
)
|
||||
16
go.sum
Normal file
16
go.sum
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
git.domandoman.xyz/doman/certchecker v0.0.2 h1:ems0cG8ULb/mSabkrsvTixXhHcZMiHrGggo4UeyOjY0=
|
||||
git.domandoman.xyz/doman/certchecker v0.0.2/go.mod h1:Ovlm5r/JfAr4LewAvXVDax6TnzBN8GwglTcYCJaWnzQ=
|
||||
github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4=
|
||||
github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
84
src/checker.go
Normal file
84
src/checker.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package src
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.domandoman.xyz/doman/certchecker"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Errors struct {
|
||||
errors []error
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (errors *Errors) append(err error) {
|
||||
errors.mutex.Lock()
|
||||
errors.errors = append(errors.errors, err)
|
||||
errors.mutex.Unlock()
|
||||
}
|
||||
|
||||
func RunCheck(config *Config) {
|
||||
localIp, err := getIp()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
errors := Errors{}
|
||||
|
||||
for _, domain := range config.Domains {
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
err := certchecker.Check(domain, config.NotifyExpirationDays)
|
||||
|
||||
if err != nil {
|
||||
errors.append(fmt.Errorf("%s: %s", domain, err))
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
domainIp, err := getDomainIp(domain)
|
||||
|
||||
if err != nil {
|
||||
errors.append(fmt.Errorf("%s: %s", domain, err))
|
||||
}
|
||||
|
||||
if domainIp != localIp {
|
||||
errors.append(fmt.Errorf("%s: DNS mismatch (%s != %s)", domain, domainIp, localIp))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if len(errors.errors) == 0 {
|
||||
fmt.Println("No errors found")
|
||||
return
|
||||
}
|
||||
|
||||
builder := strings.Builder{}
|
||||
|
||||
header := fmt.Sprintf("@here\nDuring check at: %s several errors were found:\n", time.Now().Format(time.RFC3339))
|
||||
builder.WriteString(header)
|
||||
|
||||
for _, err := range errors.errors {
|
||||
builder.WriteString(err.Error())
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
|
||||
message := builder.String()
|
||||
fmt.Println(message)
|
||||
err = sendDiscordMessage(config, message)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
40
src/config.go
Normal file
40
src/config.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package src
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/joho/godotenv"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Domains []string
|
||||
NotifyExpirationDays int
|
||||
DiscordToken string
|
||||
DiscordChannelID string
|
||||
}
|
||||
|
||||
func GetConfig() (*Config, error) {
|
||||
godotenv.Load()
|
||||
|
||||
domainsEncoded := os.Getenv("CHECK_DOMAINS")
|
||||
domains := []string{}
|
||||
err := json.Unmarshal([]byte(domainsEncoded), &domains)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
notifyExpirationDays, err := strconv.Atoi(os.Getenv("CHECK_NOTIFY_EXPIRATION_DAYS"))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Config{
|
||||
Domains: domains,
|
||||
NotifyExpirationDays: notifyExpirationDays,
|
||||
DiscordToken: os.Getenv("DISCORD_TOKEN"),
|
||||
DiscordChannelID: os.Getenv("DISCORD_CHANNEL_ID"),
|
||||
}, nil
|
||||
}
|
||||
26
src/discordInteraction.go
Normal file
26
src/discordInteraction.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package src
|
||||
|
||||
import (
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
func sendDiscordMessage(config *Config, message string) error {
|
||||
discord, err := discordgo.New("Bot " + config.DiscordToken)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = discord.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = discord.ChannelMessageSend(config.DiscordChannelID, message)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
38
src/ipTools.go
Normal file
38
src/ipTools.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package src
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type IP struct {
|
||||
Query string
|
||||
}
|
||||
|
||||
func getIp() (string, error) {
|
||||
req, err := http.Get("http://ip-api.com/json/")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer req.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var ip IP
|
||||
json.Unmarshal(body, &ip)
|
||||
|
||||
return ip.Query, nil
|
||||
}
|
||||
|
||||
func getDomainIp(domain string) (string, error) {
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ips[0].String(), nil
|
||||
}
|
||||
Loading…
Reference in a new issue