mirror of
https://github.com/MarekWojt/gertdns.git
synced 2025-12-13 04:19:51 +01:00
Password Authentication
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
gertdns
|
||||
gertdns.exe
|
||||
conf.toml
|
||||
auth.toml
|
||||
|
||||
53
README.md
53
README.md
@@ -1,2 +1,55 @@
|
||||
# gertdns
|
||||
A DynDNS server meant for gertroot
|
||||
|
||||
Running:
|
||||
```sh
|
||||
go run main.go
|
||||
```
|
||||
|
||||
Bullding:
|
||||
```sh
|
||||
go build main.go
|
||||
```
|
||||
|
||||
## Config
|
||||
`conf.toml` by default
|
||||
```toml
|
||||
[DNS]
|
||||
Port = 5353 # DNS server port
|
||||
Host = '0.0.0.0' # DNS server host
|
||||
Domains = ['example.com.'] # enabled domains, suffix with a .
|
||||
|
||||
[HTTP]
|
||||
Port = 8080 # HTTP server port
|
||||
Host = '127.0.0.1' # HTTP server host
|
||||
Socket = '' # HTTP unix socket
|
||||
SocketFileMode = 420 # File mode for HTTP unix socket in decimal (420 = 0644)
|
||||
```
|
||||
|
||||
## Users
|
||||
`auth.toml` by default
|
||||
```toml
|
||||
[someusername] # user name of the user
|
||||
Password = '1234' # password of the user
|
||||
Hashed = false # false if omitted; if false, password will be hashed
|
||||
Domains = ["subdomain.example.com."] # domains the user can register, suffix with a .
|
||||
|
||||
# ..
|
||||
```
|
||||
|
||||
## Flags
|
||||
### --enable-debug-mode
|
||||
Will output all registered records on the index page of the HTTP server.
|
||||
Type: `bool`
|
||||
Default: `false`
|
||||
|
||||
### --config-file
|
||||
Will define what config file should be used.
|
||||
Type: `string`
|
||||
Default: `conf.toml`
|
||||
|
||||
|
||||
### --auth-file
|
||||
Will define what file should be used to define users that can log in.
|
||||
Type: `string`
|
||||
Default: `auth.toml`
|
||||
|
||||
5
auth.example.toml
Normal file
5
auth.example.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[username]
|
||||
Password = '1234' # will be converted on start
|
||||
Domains = [
|
||||
'subdomain.example.com.',
|
||||
]
|
||||
84
auth/auth.go
84
auth/auth.go
@@ -1,11 +1,89 @@
|
||||
package auth
|
||||
|
||||
type AuthenticationRequest struct {
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/raja/argon2pw"
|
||||
)
|
||||
|
||||
type PasswordAuthenticationRequest struct {
|
||||
User string
|
||||
Password string
|
||||
Domain string
|
||||
}
|
||||
|
||||
func IsAuthenticated(request AuthenticationRequest) (bool, error) {
|
||||
return true, nil
|
||||
type userRaw struct {
|
||||
Password string
|
||||
Hashed bool
|
||||
Domains []string
|
||||
}
|
||||
|
||||
type user struct {
|
||||
password string
|
||||
domains map[string]string
|
||||
}
|
||||
|
||||
var parsedUsers map[string]user = map[string]user{}
|
||||
|
||||
func (user user) Authenticate(password string) (bool, error) {
|
||||
return argon2pw.CompareHashWithPassword(user.password, password)
|
||||
}
|
||||
|
||||
func (selfUser *userRaw) Tidy() (user, error) {
|
||||
if !selfUser.Hashed {
|
||||
pw, err := argon2pw.GenerateSaltedHash(selfUser.Password)
|
||||
if err != nil {
|
||||
return user{}, err
|
||||
}
|
||||
selfUser.Password = pw
|
||||
selfUser.Hashed = true
|
||||
}
|
||||
|
||||
// Create a map => faster access times
|
||||
parsedDomains := map[string]string{}
|
||||
for _, domain := range selfUser.Domains {
|
||||
parsedDomains[domain] = domain
|
||||
}
|
||||
|
||||
parsedUser := user{
|
||||
password: selfUser.Password,
|
||||
domains: parsedDomains,
|
||||
}
|
||||
|
||||
return parsedUser, nil
|
||||
}
|
||||
|
||||
func IsPasswordAuthenticated(request PasswordAuthenticationRequest) (bool, error) {
|
||||
currentUser, found := parsedUsers[request.User]
|
||||
if !found {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if _, ok := currentUser.domains[request.Domain]; !ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return currentUser.Authenticate(request.Password)
|
||||
}
|
||||
|
||||
func Init(authFilePath string) error {
|
||||
users, err := loadAuthFile(authFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for name, user := range users {
|
||||
log.Printf("%s\n", name)
|
||||
log.Printf("%+v\n", user)
|
||||
parsedUser, err := user.Tidy()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parsedUsers[name] = parsedUser
|
||||
}
|
||||
|
||||
writeAuthFile(authFilePath, users)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
45
auth/toml.go
Normal file
45
auth/toml.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
)
|
||||
|
||||
func loadAuthFile(authFilePath string) (map[string]*userRaw, error) {
|
||||
bytes, err := ioutil.ReadFile(authFilePath)
|
||||
|
||||
if err != nil {
|
||||
color.Errorln(err.Error())
|
||||
color.Warnln("Creating new authentication file")
|
||||
return writeAuthFile(authFilePath, map[string]*userRaw{})
|
||||
}
|
||||
|
||||
var users map[string]*userRaw
|
||||
err = toml.Unmarshal(bytes, &users)
|
||||
if err != nil {
|
||||
color.Errorln(err.Error())
|
||||
color.Errorln("Authentication file " + authFilePath + " could not be read as TOML file")
|
||||
return users, err
|
||||
}
|
||||
color.Infoln("Loaded authentication file " + authFilePath)
|
||||
return users, err
|
||||
}
|
||||
|
||||
func writeAuthFile(authFilePath string, users map[string]*userRaw) (map[string]*userRaw, error) {
|
||||
|
||||
authBytes, err := toml.Marshal(users)
|
||||
if err != nil {
|
||||
color.Errorln(err.Error())
|
||||
color.Errorln("Default authentication struct is not TOML conform")
|
||||
return users, err
|
||||
}
|
||||
err = os.WriteFile(authFilePath, authBytes, 0644)
|
||||
if err != nil {
|
||||
color.Errorln(err.Error())
|
||||
color.Warnln("Using default authentication without file")
|
||||
}
|
||||
return users, err
|
||||
}
|
||||
2
go.mod
2
go.mod
@@ -7,6 +7,7 @@ require (
|
||||
github.com/gookit/color v1.4.2
|
||||
github.com/miekg/dns v1.1.43
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.3
|
||||
github.com/raja/argon2pw v1.0.1
|
||||
github.com/valyala/fasthttp v1.31.0
|
||||
)
|
||||
|
||||
@@ -16,6 +17,7 @@ require (
|
||||
github.com/savsgio/gotils v0.0.0-20210921075833-21a6215cb0e4 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20211015200801-69063c4bb744 // indirect
|
||||
)
|
||||
|
||||
3
go.sum
3
go.sum
@@ -16,6 +16,8 @@ github.com/pelletier/go-toml/v2 v2.0.0-beta.3 h1:PNCTU4naEJ8mKal97P3A2qDU74QRQGl
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.3/go.mod h1:aNseLYu/uKskg0zpr/kbr2z8yGuWtotWf/0BpGIAL2Y=
|
||||
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/raja/argon2pw v1.0.1 h1:RIUM12+uQdj5/cWQLlEmZDD8xj5kQN1X9kTK0xfXjGQ=
|
||||
github.com/raja/argon2pw v1.0.1/go.mod h1:idX/fPqwjX31YMTF2iIpEpNApV2YbQhSFr4iIhJaqp4=
|
||||
github.com/savsgio/gotils v0.0.0-20210921075833-21a6215cb0e4 h1:ocK/D6lCgLji37Z2so4xhMl46se1ntReQQCUIU4BWI8=
|
||||
github.com/savsgio/gotils v0.0.0-20210921075833-21a6215cb0e4/go.mod h1:oejLrk1Y/5zOF+c/aHtXqn3TFlzzbAgPWg8zBiAHDas=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -29,6 +31,7 @@ github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
|
||||
8
main.go
8
main.go
@@ -4,6 +4,7 @@ import (
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"github.com/MarekWojt/gertdns/auth"
|
||||
"github.com/MarekWojt/gertdns/config"
|
||||
"github.com/MarekWojt/gertdns/dns"
|
||||
"github.com/MarekWojt/gertdns/web"
|
||||
@@ -11,7 +12,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
configFile = flag.String("configFile", "conf.toml", "Path to configuration file")
|
||||
configFile = flag.String("config-file", "conf.toml", "Path to configuration file")
|
||||
authFile = flag.String("auth-file", "auth.toml", "Path to authentication file")
|
||||
)
|
||||
|
||||
type dnsResult struct {
|
||||
@@ -29,6 +31,10 @@ func main() {
|
||||
|
||||
dns.Init()
|
||||
web.Init()
|
||||
err = auth.Init(*authFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize authentication module: %s\n", err.Error())
|
||||
}
|
||||
|
||||
webChan := make(chan error)
|
||||
dnsChan := make(chan dnsResult)
|
||||
|
||||
@@ -108,13 +108,13 @@ func authenticatedRequest(request func(ctx *fasthttp.RequestCtx)) func(ctx *fast
|
||||
return
|
||||
}
|
||||
|
||||
authRequest := auth.AuthenticationRequest{
|
||||
authRequest := auth.PasswordAuthenticationRequest{
|
||||
Domain: domain,
|
||||
User: user,
|
||||
Password: password,
|
||||
}
|
||||
|
||||
authenticated, err := auth.IsAuthenticated(authRequest)
|
||||
authenticated, err := auth.IsPasswordAuthenticated(authRequest)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user