mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-29 18:33:05 +00:00
commit
fb933b7d41
4 changed files with 93 additions and 39 deletions
56
api.go
56
api.go
|
@ -1,10 +1,12 @@
|
||||||
package headscale
|
package headscale
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -38,6 +40,28 @@ func (h *Headscale) KeyHandler(ctx *gin.Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type registerWebAPITemplateConfig struct {
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
var registerWebAPITemplate = template.Must(
|
||||||
|
template.New("registerweb").Parse(`<html>
|
||||||
|
<body>
|
||||||
|
<h1>headscale</h1>
|
||||||
|
<p>
|
||||||
|
Run the command below in the headscale server to add this machine to your network:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>
|
||||||
|
<b>headscale -n NAMESPACE nodes register --key {{.Key}}</b>
|
||||||
|
</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>`),
|
||||||
|
)
|
||||||
|
|
||||||
// RegisterWebAPI shows a simple message in the browser to point to the CLI
|
// RegisterWebAPI shows a simple message in the browser to point to the CLI
|
||||||
// Listens in /register.
|
// Listens in /register.
|
||||||
func (h *Headscale) RegisterWebAPI(ctx *gin.Context) {
|
func (h *Headscale) RegisterWebAPI(ctx *gin.Context) {
|
||||||
|
@ -48,24 +72,22 @@ func (h *Headscale) RegisterWebAPI(ctx *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(`
|
var content bytes.Buffer
|
||||||
<html>
|
if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{
|
||||||
<body>
|
Key: machineKeyStr,
|
||||||
<h1>headscale</h1>
|
}); err != nil {
|
||||||
<p>
|
log.Error().
|
||||||
Run the command below in the headscale server to add this machine to your network:
|
Str("func", "RegisterWebAPI").
|
||||||
</p>
|
Err(err).
|
||||||
|
Msg("Could not render register web API template")
|
||||||
|
ctx.Data(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
"text/html; charset=utf-8",
|
||||||
|
[]byte("Could not render register web API template"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
<p>
|
ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes())
|
||||||
<code>
|
|
||||||
<b>headscale -n NAMESPACE nodes register --key %s</b>
|
|
||||||
</code>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
`, machineKeyStr)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegistrationHandler handles the actual registration process of a machine
|
// RegistrationHandler handles the actual registration process of a machine
|
||||||
|
|
|
@ -2,8 +2,8 @@ package headscale
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
|
|
72
oidc.go
72
oidc.go
|
@ -1,11 +1,13 @@
|
||||||
package headscale
|
package headscale
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -108,6 +110,22 @@ func (h *Headscale) RegisterOIDC(ctx *gin.Context) {
|
||||||
ctx.Redirect(http.StatusFound, authURL)
|
ctx.Redirect(http.StatusFound, authURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type oidcCallbackTemplateConfig struct {
|
||||||
|
User string
|
||||||
|
Verb string
|
||||||
|
}
|
||||||
|
|
||||||
|
var oidcCallbackTemplate = template.Must(
|
||||||
|
template.New("oidccallback").Parse(`<html>
|
||||||
|
<body>
|
||||||
|
<h1>headscale</h1>
|
||||||
|
<p>
|
||||||
|
{{.Verb}} as {{.User}}, you can now close this window.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>`),
|
||||||
|
)
|
||||||
|
|
||||||
// OIDCCallback handles the callback from the OIDC endpoint
|
// OIDCCallback handles the callback from the OIDC endpoint
|
||||||
// Retrieves the mkey from the state cache and adds the machine to the users email namespace
|
// Retrieves the mkey from the state cache and adds the machine to the users email namespace
|
||||||
// TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities
|
// TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities
|
||||||
|
@ -239,17 +257,24 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) {
|
||||||
|
|
||||||
h.RefreshMachine(machine, requestedTime)
|
h.RefreshMachine(machine, requestedTime)
|
||||||
|
|
||||||
ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(`
|
var content bytes.Buffer
|
||||||
<html>
|
if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{
|
||||||
<body>
|
User: claims.Email,
|
||||||
<h1>headscale</h1>
|
Verb: "Reauthenticated",
|
||||||
<p>
|
}); err != nil {
|
||||||
Reuthenticated as %s, you can now close this window.
|
log.Error().
|
||||||
</p>
|
Str("func", "OIDCCallback").
|
||||||
</body>
|
Str("type", "reauthenticate").
|
||||||
</html>
|
Err(err).
|
||||||
|
Msg("Could not render OIDC callback template")
|
||||||
|
ctx.Data(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
"text/html; charset=utf-8",
|
||||||
|
[]byte("Could not render OIDC callback template"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
`, claims.Email)))
|
ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -314,17 +339,24 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) {
|
||||||
h.db.Save(&machine)
|
h.db.Save(&machine)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(`
|
var content bytes.Buffer
|
||||||
<html>
|
if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{
|
||||||
<body>
|
User: claims.Email,
|
||||||
<h1>headscale</h1>
|
Verb: "Authenticated",
|
||||||
<p>
|
}); err != nil {
|
||||||
Authenticated as %s, you can now close this window.
|
log.Error().
|
||||||
</p>
|
Str("func", "OIDCCallback").
|
||||||
</body>
|
Str("type", "authenticate").
|
||||||
</html>
|
Err(err).
|
||||||
|
Msg("Could not render OIDC callback template")
|
||||||
|
ctx.Data(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
"text/html; charset=utf-8",
|
||||||
|
[]byte("Could not render OIDC callback template"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
`, claims.Email)))
|
ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ package headscale
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
Loading…
Reference in a new issue