parent
dd7953b452
commit
6155f28671
|
@ -1,2 +1,2 @@
|
|||
.idea/
|
||||
/mcm-register*
|
||||
/mineauth*
|
|
@ -0,0 +1,24 @@
|
|||
# mineauth
|
||||
|
||||
Users can log into a server (which validates their account) and you can run hooks after.
|
||||
|
||||
```text
|
||||
Usage of mineauth:
|
||||
-community string
|
||||
URL to community
|
||||
-debug
|
||||
Debug Logging
|
||||
-hook value
|
||||
Hook to run
|
||||
-ping string
|
||||
Message for the server list (default "Login to authenticate!")
|
||||
-port int
|
||||
Port to listen on (default 25565)
|
||||
-timeout int
|
||||
HTTP timeout (default 15)
|
||||
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
|
@ -0,0 +1,76 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
//go:embed webhook.txt
|
||||
var webhookURL string
|
||||
|
||||
type profile struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
func (p *profile) UUID() string {
|
||||
return fmt.Sprintf("%s-%s-%s-%s-%s", p.ID[:8], p.ID[8:12], p.ID[12:16], p.ID[16:20], p.ID[20:32])
|
||||
}
|
||||
|
||||
func main() {
|
||||
var profile profile
|
||||
if err := json.NewDecoder(os.Stdin).Decode(&profile); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
payloadHook := webhook{
|
||||
Username: profile.Name,
|
||||
Embeds: []embed{
|
||||
{
|
||||
Fields: []field{
|
||||
{
|
||||
Name: "UUID",
|
||||
Value: profile.UUID(),
|
||||
},
|
||||
{
|
||||
Name: "IP",
|
||||
Value: profile.IP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
payload, err := json.Marshal(payloadHook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
res, err := http.Post(webhookURL, "application/json", bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
panic(fmt.Errorf("received non-200 status: %s", res.Status))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type webhook struct {
|
||||
Username string `json:"username"`
|
||||
Embeds []embed `json:"embeds"`
|
||||
}
|
||||
|
||||
type embed struct {
|
||||
Fields []field `json:"fields"`
|
||||
}
|
||||
|
||||
type field struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
https://discord.com/api/webhooks/<id>/<token>
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
|||
module git.canopymc.net/Etzelia/mcm-register
|
||||
module git.canopymc.net/Etzelia/mineauth
|
||||
|
||||
go 1.16
|
||||
|
||||
|
|
27
main.go
27
main.go
|
@ -2,19 +2,27 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/peterbourgon/ff/v3"
|
||||
"github.com/peterbourgon/ff/v3/fftoml"
|
||||
"go.jolheiser.com/beaver"
|
||||
"git.canopymc.net/Etzelia/mineauth/server"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/peterbourgon/ff/v3"
|
||||
"github.com/peterbourgon/ff/v3/fftoml"
|
||||
"go.jolheiser.com/beaver"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fs := flag.NewFlagSet("afk", flag.ExitOnError)
|
||||
fs := flag.NewFlagSet("mineauth", flag.ExitOnError)
|
||||
portFlag := fs.Int("port", 25565, "Port to listen on")
|
||||
timeoutFlag := fs.Int("timeout", 15, "HTTP timeout")
|
||||
discordFlag := fs.String("discord", "", "Discord invite link")
|
||||
pingMessageFlag := fs.String("ping", "Login to authenticate!", "Message for the server list")
|
||||
communityFlag := fs.String("community", "", "URL to community")
|
||||
hooksFlag := make([]string, 0)
|
||||
fs.Func("hook", "Hook to run", func(hook string) error {
|
||||
hooksFlag = append(hooksFlag, hook)
|
||||
return nil
|
||||
})
|
||||
debugFlag := fs.Bool("debug", false, "Debug Logging")
|
||||
if err := ff.Parse(fs, os.Args[1:],
|
||||
ff.WithEnvVarPrefix("MCM_REGISTER"),
|
||||
|
@ -31,13 +39,18 @@ func main() {
|
|||
|
||||
http.DefaultClient.Timeout = time.Second * time.Duration(*timeoutFlag)
|
||||
|
||||
server, err := NewServer(*discordFlag)
|
||||
serv, err := server.New(server.Options{
|
||||
PingMessage: *pingMessageFlag,
|
||||
CommunityURL: *communityFlag,
|
||||
Hooks: hooksFlag,
|
||||
})
|
||||
if err != nil {
|
||||
beaver.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := server.Start(*portFlag); err != nil {
|
||||
beaver.Infof("Listening on http://localhost:%d", *portFlag)
|
||||
if err := serv.Start(*portFlag); err != nil {
|
||||
beaver.Error(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package server
|
||||
|
||||
import "crypto/cipher"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -9,11 +9,12 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Tnze/go-mc/net"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/Tnze/go-mc/net"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
var hasJoinedURL = func() *url.URL {
|
||||
|
@ -37,6 +38,7 @@ func (s *Server) encryptionRequest(conn net.Conn) ([]byte, error) {
|
|||
type profile struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
func (p *profile) UUID() string {
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
@ -1,9 +1,10 @@
|
|||
package main
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/Tnze/go-mc/bot"
|
||||
"github.com/Tnze/go-mc/chat"
|
||||
"github.com/Tnze/go-mc/net"
|
||||
|
@ -22,7 +23,7 @@ func (s *Server) acceptListPing(conn net.Conn) {
|
|||
|
||||
switch p.ID {
|
||||
case 0x00:
|
||||
err = conn.WritePacket(pk.Marshal(0x00, pk.String(listResp())))
|
||||
err = conn.WritePacket(pk.Marshal(0x00, pk.String(s.listResp())))
|
||||
case 0x01:
|
||||
err = conn.WritePacket(p)
|
||||
}
|
||||
|
@ -38,7 +39,7 @@ type player struct {
|
|||
}
|
||||
|
||||
// listResp return server status as JSON string
|
||||
func listResp() string {
|
||||
func (s *Server) listResp() string {
|
||||
var list struct {
|
||||
Version struct {
|
||||
Name string `json:"name"`
|
||||
|
@ -58,7 +59,7 @@ func listResp() string {
|
|||
list.Players.Max = 0
|
||||
list.Players.Online = 0
|
||||
list.Players.Sample = []player{}
|
||||
list.Description = chat.Message{Text: "Login to register!"}
|
||||
list.Description = chat.Message{Text: s.opts.PingMessage}
|
||||
list.FavIcon = fmt.Sprintf("data:image/png;base64,%s", base64.StdEncoding.EncodeToString(favicon))
|
||||
|
||||
data, err := json.Marshal(list)
|
|
@ -1,28 +1,39 @@
|
|||
package main
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Tnze/go-mc/chat"
|
||||
"github.com/Tnze/go-mc/net"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"github.com/google/uuid"
|
||||
"go.jolheiser.com/beaver"
|
||||
gonet "net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed favicon.png
|
||||
var favicon []byte
|
||||
|
||||
type Server struct {
|
||||
privateKey *rsa.PrivateKey
|
||||
publicKey []byte
|
||||
discordInvite string
|
||||
privateKey *rsa.PrivateKey
|
||||
publicKey []byte
|
||||
opts Options
|
||||
}
|
||||
|
||||
func NewServer(discordInvite string) (*Server, error) {
|
||||
type Options struct {
|
||||
CommunityURL string
|
||||
PingMessage string
|
||||
Hooks []string
|
||||
}
|
||||
|
||||
func New(opts Options) (*Server, error) {
|
||||
private, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generate private key: %v", err)
|
||||
|
@ -36,14 +47,13 @@ func NewServer(discordInvite string) (*Server, error) {
|
|||
private.Precompute()
|
||||
|
||||
return &Server{
|
||||
privateKey: private,
|
||||
publicKey: public,
|
||||
discordInvite: discordInvite,
|
||||
privateKey: private,
|
||||
publicKey: public,
|
||||
opts: opts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Start(port int) error {
|
||||
beaver.Infof("Listening on http://localhost:%d", port)
|
||||
l, err := net.ListenMC(fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
return fmt.Errorf("listen error: %v", err)
|
||||
|
@ -96,7 +106,34 @@ func (s *Server) handlePlaying(conn net.Conn) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO Register
|
||||
profile.IP, _, err = gonet.SplitHostPort(conn.Socket.RemoteAddr().String())
|
||||
if err != nil {
|
||||
beaver.Errorf("could not get user IP: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(profile)
|
||||
if err != nil {
|
||||
beaver.Errorf("could not marshal payload: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, hook := range s.opts.Hooks {
|
||||
go func(h string) {
|
||||
s := strings.Split(h, " ")
|
||||
var args []string
|
||||
if len(s) > 1 {
|
||||
args = s[1:]
|
||||
}
|
||||
cmd := exec.Command(s[0], args...)
|
||||
cmd.Stdin = bytes.NewReader(payload)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
beaver.Errorf("could not run hook `%s`: %v", h, err)
|
||||
beaver.Warn(string(out))
|
||||
}
|
||||
}(hook)
|
||||
}
|
||||
|
||||
econn, err := encryptedConn(conn, secret)
|
||||
if err != nil {
|
||||
|
@ -104,9 +141,9 @@ func (s *Server) handlePlaying(conn net.Conn) {
|
|||
return
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("Thanks for registering, %s!", profile.Name)
|
||||
if s.discordInvite != "" {
|
||||
msg += fmt.Sprintf("\n\nJoin the Discord\n%s", s.discordInvite)
|
||||
msg := fmt.Sprintf("Thanks for authenticating, %s!", profile.Name)
|
||||
if s.opts.CommunityURL != "" {
|
||||
msg += fmt.Sprintf("\n\nJoin the community\n%s", s.opts.CommunityURL)
|
||||
}
|
||||
packet := pk.Marshal(0x00,
|
||||
chat.Message{Text: msg},
|
Loading…
Reference in New Issue