[project] init

This commit is contained in:
Piotr Domański 2024-07-25 21:20:00 +02:00
commit dfec6f5cdc
13 changed files with 294 additions and 0 deletions

4
.dockerignore Normal file
View file

@ -0,0 +1,4 @@
!src
!cmd
!go.mod
!go.sum

25
.gitignore vendored Normal file
View 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
View 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
View file

15
cmd/main.go Normal file
View 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
View file

@ -0,0 +1,9 @@
services:
app:
image: serverchecker
restart: unless-stopped
build:
context: .
dockerfile: Dockerfile
env_file:
- .env

4
env.template Normal file
View file

@ -0,0 +1,4 @@
DISCORD_TOKEN=""
DISCORD_CHANNEL_ID=""
CHECK_DOMAINS="[\"google.com\"]"
CHECK_NOTIFY_EXPIRATION_DAYS=7

15
go.mod Normal file
View 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
View 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
View 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
View 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
View 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
View 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
}