mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-01-08 19:00:25 +00:00
Implement initial Telegram integration
This commit is contained in:
parent
9ad9db9825
commit
df78f75efb
@ -34,6 +34,11 @@ var (
|
|||||||
CommonScripts []string
|
CommonScripts []string
|
||||||
ViewScripts []string
|
ViewScripts []string
|
||||||
EditScripts []string
|
EditScripts []string
|
||||||
|
|
||||||
|
// TelegramEnabled if both TelegramBotToken and TelegramBotName are not empty strings.
|
||||||
|
TelegramEnabled bool
|
||||||
|
TelegramBotToken string
|
||||||
|
TelegramBotName string
|
||||||
)
|
)
|
||||||
|
|
||||||
// WikiDir is a full path to the wiki storage directory, which also must be a
|
// WikiDir is a full path to the wiki storage directory, which also must be a
|
||||||
@ -49,6 +54,7 @@ type Config struct {
|
|||||||
Network
|
Network
|
||||||
Authorization
|
Authorization
|
||||||
CustomScripts `comment:"You can specify additional scripts to load on different kinds of pages, delimited by a comma ',' sign."`
|
CustomScripts `comment:"You can specify additional scripts to load on different kinds of pages, delimited by a comma ',' sign."`
|
||||||
|
Telegram `comment:"You can enable Telegram authorization. Follow these instructions: https://core.telegram.org/widgets/login#setting-up-a-bot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hyphae is a section of Config which has fields related to special hyphae.
|
// Hyphae is a section of Config which has fields related to special hyphae.
|
||||||
@ -85,6 +91,12 @@ type Authorization struct {
|
|||||||
Locked bool `comment:"Set if users have to authorize to see anything on the wiki."`
|
Locked bool `comment:"Set if users have to authorize to see anything on the wiki."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Telegram is the section of Config that sets Telegram authorization.
|
||||||
|
type Telegram struct {
|
||||||
|
TelegramBotToken string `comment:"Token of your bot.`
|
||||||
|
TelegramBotName string `comment:"Username of your bot, sans @.`
|
||||||
|
}
|
||||||
|
|
||||||
// ReadConfigFile reads a config on the given path and stores the
|
// ReadConfigFile reads a config on the given path and stores the
|
||||||
// configuration. Call it sometime during the initialization.
|
// configuration. Call it sometime during the initialization.
|
||||||
func ReadConfigFile(path string) error {
|
func ReadConfigFile(path string) error {
|
||||||
@ -111,6 +123,10 @@ func ReadConfigFile(path string) error {
|
|||||||
ViewScripts: []string{},
|
ViewScripts: []string{},
|
||||||
EditScripts: []string{},
|
EditScripts: []string{},
|
||||||
},
|
},
|
||||||
|
Telegram: Telegram{
|
||||||
|
TelegramBotToken: "",
|
||||||
|
TelegramBotName: "",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := ini.Load(path)
|
f, err := ini.Load(path)
|
||||||
@ -158,6 +174,9 @@ func ReadConfigFile(path string) error {
|
|||||||
CommonScripts = cfg.CommonScripts
|
CommonScripts = cfg.CommonScripts
|
||||||
ViewScripts = cfg.ViewScripts
|
ViewScripts = cfg.ViewScripts
|
||||||
EditScripts = cfg.EditScripts
|
EditScripts = cfg.EditScripts
|
||||||
|
TelegramBotToken = cfg.TelegramBotToken
|
||||||
|
TelegramBotName = cfg.TelegramBotName
|
||||||
|
TelegramEnabled = (TelegramBotToken != "") && (TelegramBotName != "")
|
||||||
|
|
||||||
// This URL makes much more sense.
|
// This URL makes much more sense.
|
||||||
if URL == "" {
|
if URL == "" {
|
||||||
|
39
user/net.go
39
user/net.go
@ -5,6 +5,11 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
||||||
"github.com/bouncepaw/mycorrhiza/util"
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
@ -65,6 +70,8 @@ func Register(username, password, group string, force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoginDataHTTP logs such user in and returns string representation of an error if there is any.
|
// LoginDataHTTP logs such user in and returns string representation of an error if there is any.
|
||||||
|
//
|
||||||
|
// The HTTP parameters are used for setting header status (bad request, if it is bad) and saving a cookie.
|
||||||
func LoginDataHTTP(w http.ResponseWriter, rq *http.Request, username, password string) string {
|
func LoginDataHTTP(w http.ResponseWriter, rq *http.Request, username, password string) string {
|
||||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||||
if !HasUsername(username) {
|
if !HasUsername(username) {
|
||||||
@ -106,3 +113,35 @@ func cookie(name_suffix, val string, t time.Time) *http.Cookie {
|
|||||||
Path: "/",
|
Path: "/",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TelegramAuthParamsAreValid is true if the given params are ok.
|
||||||
|
func TelegramAuthParamsAreValid(params map[string][]string) bool {
|
||||||
|
// According to the Telegram documentation,
|
||||||
|
// > You can verify the authentication and the integrity of the data received by comparing the received hash parameter with the hexadecimal representation of the HMAC-SHA-256 signature of the data-check-string with the SHA256 hash of the bot's token used as a secret key.
|
||||||
|
tokenHash := sha256.New()
|
||||||
|
tokenHash.Write([]byte(cfg.TelegramBotToken))
|
||||||
|
secretKey := tokenHash.Sum(nil)
|
||||||
|
|
||||||
|
hash := hmac.New(sha256.New, secretKey)
|
||||||
|
hash.Write([]byte(telegramDataCheckString(params)))
|
||||||
|
hexHash := hex.EncodeToString(hash.Sum(nil))
|
||||||
|
|
||||||
|
passedHash := params["hash"][0]
|
||||||
|
return passedHash == hexHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// According to the Telegram documentation,
|
||||||
|
// > Data-check-string is a concatenation of all received fields, sorted in alphabetical order, in the format key=<value> with a line feed character ('\n', 0x0A) used as separator – e.g., 'auth_date=<auth_date>\nfirst_name=<first_name>\nid=<id>\nusername=<username>'.
|
||||||
|
//
|
||||||
|
// Note that hash is not used here.
|
||||||
|
func telegramDataCheckString(params map[string][]string) string {
|
||||||
|
var lines []string
|
||||||
|
for key, value := range params {
|
||||||
|
if key == "hash" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines = append(lines, fmt.Sprintf("%s=%s", key, value[0]))
|
||||||
|
}
|
||||||
|
sort.Strings(lines)
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
@ -44,6 +44,7 @@ var groups = []string{
|
|||||||
"anon",
|
"anon",
|
||||||
"editor",
|
"editor",
|
||||||
"trusted",
|
"trusted",
|
||||||
|
"telegram",
|
||||||
"moderator",
|
"moderator",
|
||||||
"admin",
|
"admin",
|
||||||
}
|
}
|
||||||
@ -53,6 +54,7 @@ var groupRight = map[string]int{
|
|||||||
"anon": 0,
|
"anon": 0,
|
||||||
"editor": 1,
|
"editor": 1,
|
||||||
"trusted": 2,
|
"trusted": 2,
|
||||||
|
"telegram": 2,
|
||||||
"moderator": 3,
|
"moderator": 3,
|
||||||
"admin": 4,
|
"admin": 4,
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<a class="btn btn_weak" href="/{%s rq.URL.RawQuery %}">Cancel</a>
|
<a class="btn btn_weak" href="/{%s rq.URL.RawQuery %}">Cancel</a>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
{%= telegramWidgetHTML() %}
|
||||||
{% elseif cfg.UseAuth %}
|
{% elseif cfg.UseAuth %}
|
||||||
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
|
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
|
||||||
<p><a href="/{%s rq.URL.RawQuery %}">← Go back</a></p>
|
<p><a href="/{%s rq.URL.RawQuery %}">← Go back</a></p>
|
||||||
@ -55,6 +56,7 @@
|
|||||||
<a class="btn btn_weak" href="/">Cancel</a>
|
<a class="btn btn_weak" href="/">Cancel</a>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
{%= telegramWidgetHTML() %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Authentication is disabled. You can make edits anonymously.</p>
|
<p>Authentication is disabled. You can make edits anonymously.</p>
|
||||||
<p><a class="btn btn_weak" href="/">← Go home</a></p>
|
<p><a class="btn btn_weak" href="/">← Go home</a></p>
|
||||||
@ -64,6 +66,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfunc %}
|
{% endfunc %}
|
||||||
|
|
||||||
|
Telegram auth widget was requested by Yogurt. As you can see, we don't offer user administrators control over it. Of course we don't.
|
||||||
|
{% func telegramWidgetHTML() %}
|
||||||
|
{% if cfg.TelegramEnabled %}
|
||||||
|
<script async src="https://telegram.org/js/telegram-widget.js?15" data-telegram-login="{%s cfg.TelegramBotName %}" data-size="medium" data-userpic="false" data-auth-url="{%s cfg.URL %}/telegram-login"></script>
|
||||||
|
{% endif %}
|
||||||
|
{% endfunc %}
|
||||||
|
|
||||||
{% func LoginErrorHTML(err string) %}
|
{% func LoginErrorHTML(err string) %}
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<main class="main-width">
|
<main class="main-width">
|
||||||
|
@ -66,82 +66,87 @@ func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) {
|
|||||||
</form>
|
</form>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:26
|
//line views/auth.qtpl:26
|
||||||
} else if cfg.UseAuth {
|
streamtelegramWidgetHTML(qw422016)
|
||||||
//line views/auth.qtpl:26
|
//line views/auth.qtpl:26
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
|
`)
|
||||||
|
//line views/auth.qtpl:27
|
||||||
|
} else if cfg.UseAuth {
|
||||||
|
//line views/auth.qtpl:27
|
||||||
|
qw422016.N().S(`
|
||||||
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
|
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
|
||||||
<p><a href="/`)
|
<p><a href="/`)
|
||||||
//line views/auth.qtpl:28
|
//line views/auth.qtpl:29
|
||||||
qw422016.E().S(rq.URL.RawQuery)
|
qw422016.E().S(rq.URL.RawQuery)
|
||||||
//line views/auth.qtpl:28
|
//line views/auth.qtpl:29
|
||||||
qw422016.N().S(`">← Go back</a></p>
|
qw422016.N().S(`">← Go back</a></p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:29
|
//line views/auth.qtpl:30
|
||||||
} else {
|
} else {
|
||||||
//line views/auth.qtpl:29
|
//line views/auth.qtpl:30
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p>Authentication is disabled. You can make edits anonymously.</p>
|
<p>Authentication is disabled. You can make edits anonymously.</p>
|
||||||
<p><a href="/`)
|
<p><a href="/`)
|
||||||
//line views/auth.qtpl:31
|
//line views/auth.qtpl:32
|
||||||
qw422016.E().S(rq.URL.RawQuery)
|
qw422016.E().S(rq.URL.RawQuery)
|
||||||
//line views/auth.qtpl:31
|
//line views/auth.qtpl:32
|
||||||
qw422016.N().S(`">← Go back</a></p>
|
qw422016.N().S(`">← Go back</a></p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:32
|
//line views/auth.qtpl:33
|
||||||
}
|
}
|
||||||
//line views/auth.qtpl:32
|
//line views/auth.qtpl:33
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
func WriteRegisterHTML(qq422016 qtio422016.Writer, rq *http.Request) {
|
func WriteRegisterHTML(qq422016 qtio422016.Writer, rq *http.Request) {
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
StreamRegisterHTML(qw422016, rq)
|
StreamRegisterHTML(qw422016, rq)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
func RegisterHTML(rq *http.Request) string {
|
func RegisterHTML(rq *http.Request) string {
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
WriteRegisterHTML(qb422016, rq)
|
WriteRegisterHTML(qb422016, rq)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
return qs422016
|
return qs422016
|
||||||
//line views/auth.qtpl:36
|
//line views/auth.qtpl:37
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:38
|
//line views/auth.qtpl:39
|
||||||
func StreamLoginHTML(qw422016 *qt422016.Writer) {
|
func StreamLoginHTML(qw422016 *qt422016.Writer) {
|
||||||
//line views/auth.qtpl:38
|
//line views/auth.qtpl:39
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<main class="main-width">
|
<main class="main-width">
|
||||||
<section>
|
<section>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:42
|
//line views/auth.qtpl:43
|
||||||
if cfg.UseAuth {
|
if cfg.UseAuth {
|
||||||
//line views/auth.qtpl:42
|
//line views/auth.qtpl:43
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
|
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
|
||||||
<fieldset class="modal__fieldset">
|
<fieldset class="modal__fieldset">
|
||||||
<legend class="modal__title">Log in to `)
|
<legend class="modal__title">Log in to `)
|
||||||
//line views/auth.qtpl:45
|
//line views/auth.qtpl:46
|
||||||
qw422016.E().S(cfg.WikiName)
|
qw422016.E().S(cfg.WikiName)
|
||||||
//line views/auth.qtpl:45
|
//line views/auth.qtpl:46
|
||||||
qw422016.N().S(`</legend>
|
qw422016.N().S(`</legend>
|
||||||
<label for="login-form__username">Username</label>
|
<label for="login-form__username">Username</label>
|
||||||
<br>
|
<br>
|
||||||
@ -156,184 +161,244 @@ func StreamLoginHTML(qw422016 *qt422016.Writer) {
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:58
|
//line views/auth.qtpl:59
|
||||||
|
streamtelegramWidgetHTML(qw422016)
|
||||||
|
//line views/auth.qtpl:59
|
||||||
|
qw422016.N().S(`
|
||||||
|
`)
|
||||||
|
//line views/auth.qtpl:60
|
||||||
} else {
|
} else {
|
||||||
//line views/auth.qtpl:58
|
//line views/auth.qtpl:60
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p>Authentication is disabled. You can make edits anonymously.</p>
|
<p>Authentication is disabled. You can make edits anonymously.</p>
|
||||||
<p><a class="btn btn_weak" href="/">← Go home</a></p>
|
<p><a class="btn btn_weak" href="/">← Go home</a></p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:61
|
//line views/auth.qtpl:63
|
||||||
}
|
}
|
||||||
//line views/auth.qtpl:61
|
//line views/auth.qtpl:63
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
func WriteLoginHTML(qq422016 qtio422016.Writer) {
|
func WriteLoginHTML(qq422016 qtio422016.Writer) {
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
StreamLoginHTML(qw422016)
|
StreamLoginHTML(qw422016)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
func LoginHTML() string {
|
func LoginHTML() string {
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
WriteLoginHTML(qb422016)
|
WriteLoginHTML(qb422016)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
return qs422016
|
return qs422016
|
||||||
//line views/auth.qtpl:65
|
//line views/auth.qtpl:67
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:67
|
// Telegram auth widget was requested by Yogurt. As you can see, we don't offer user administrators control over it. Of course we don't.
|
||||||
|
|
||||||
|
//line views/auth.qtpl:70
|
||||||
|
func streamtelegramWidgetHTML(qw422016 *qt422016.Writer) {
|
||||||
|
//line views/auth.qtpl:70
|
||||||
|
qw422016.N().S(`
|
||||||
|
`)
|
||||||
|
//line views/auth.qtpl:71
|
||||||
|
if cfg.TelegramEnabled {
|
||||||
|
//line views/auth.qtpl:71
|
||||||
|
qw422016.N().S(`
|
||||||
|
<script async src="https://telegram.org/js/telegram-widget.js?15" data-telegram-login="`)
|
||||||
|
//line views/auth.qtpl:72
|
||||||
|
qw422016.E().S(cfg.TelegramBotName)
|
||||||
|
//line views/auth.qtpl:72
|
||||||
|
qw422016.N().S(`" data-size="medium" data-userpic="false" data-auth-url="`)
|
||||||
|
//line views/auth.qtpl:72
|
||||||
|
qw422016.E().S(cfg.URL)
|
||||||
|
//line views/auth.qtpl:72
|
||||||
|
qw422016.N().S(`/telegram-login"></script>
|
||||||
|
`)
|
||||||
|
//line views/auth.qtpl:73
|
||||||
|
}
|
||||||
|
//line views/auth.qtpl:73
|
||||||
|
qw422016.N().S(`
|
||||||
|
`)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
}
|
||||||
|
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
func writetelegramWidgetHTML(qq422016 qtio422016.Writer) {
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
streamtelegramWidgetHTML(qw422016)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
qt422016.ReleaseWriter(qw422016)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
}
|
||||||
|
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
func telegramWidgetHTML() string {
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
writetelegramWidgetHTML(qb422016)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
qs422016 := string(qb422016.B)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
return qs422016
|
||||||
|
//line views/auth.qtpl:74
|
||||||
|
}
|
||||||
|
|
||||||
|
//line views/auth.qtpl:76
|
||||||
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
|
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
|
||||||
//line views/auth.qtpl:67
|
//line views/auth.qtpl:76
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<main class="main-width">
|
<main class="main-width">
|
||||||
<section>
|
<section>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:71
|
//line views/auth.qtpl:80
|
||||||
switch err {
|
switch err {
|
||||||
//line views/auth.qtpl:72
|
//line views/auth.qtpl:81
|
||||||
case "unknown username":
|
case "unknown username":
|
||||||
//line views/auth.qtpl:72
|
//line views/auth.qtpl:81
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p class="error">Unknown username.</p>
|
<p class="error">Unknown username.</p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:74
|
//line views/auth.qtpl:83
|
||||||
case "wrong password":
|
case "wrong password":
|
||||||
//line views/auth.qtpl:74
|
//line views/auth.qtpl:83
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p class="error">Wrong password.</p>
|
<p class="error">Wrong password.</p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:76
|
//line views/auth.qtpl:85
|
||||||
default:
|
default:
|
||||||
//line views/auth.qtpl:76
|
//line views/auth.qtpl:85
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p class="error">`)
|
<p class="error">`)
|
||||||
//line views/auth.qtpl:77
|
//line views/auth.qtpl:86
|
||||||
qw422016.E().S(err)
|
qw422016.E().S(err)
|
||||||
//line views/auth.qtpl:77
|
//line views/auth.qtpl:86
|
||||||
qw422016.N().S(`</p>
|
qw422016.N().S(`</p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:78
|
//line views/auth.qtpl:87
|
||||||
}
|
}
|
||||||
//line views/auth.qtpl:78
|
//line views/auth.qtpl:87
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p><a href="/login">← Try again</a></p>
|
<p><a href="/login">← Try again</a></p>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
|
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
StreamLoginErrorHTML(qw422016, err)
|
StreamLoginErrorHTML(qw422016, err)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
func LoginErrorHTML(err string) string {
|
func LoginErrorHTML(err string) string {
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
WriteLoginErrorHTML(qb422016, err)
|
WriteLoginErrorHTML(qb422016, err)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
return qs422016
|
return qs422016
|
||||||
//line views/auth.qtpl:83
|
//line views/auth.qtpl:92
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:85
|
//line views/auth.qtpl:94
|
||||||
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) {
|
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) {
|
||||||
//line views/auth.qtpl:85
|
//line views/auth.qtpl:94
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<main class="main-width">
|
<main class="main-width">
|
||||||
<section>
|
<section>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:89
|
//line views/auth.qtpl:98
|
||||||
if can {
|
if can {
|
||||||
//line views/auth.qtpl:89
|
//line views/auth.qtpl:98
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<h1>Log out?</h1>
|
<h1>Log out?</h1>
|
||||||
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
|
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
|
||||||
<p><a href="/">Cancel</a></p>
|
<p><a href="/">Cancel</a></p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:93
|
//line views/auth.qtpl:102
|
||||||
} else {
|
} else {
|
||||||
//line views/auth.qtpl:93
|
//line views/auth.qtpl:102
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<p>You cannot log out because you are not logged in.</p>
|
<p>You cannot log out because you are not logged in.</p>
|
||||||
<p><a href="/login">Login</a></p>
|
<p><a href="/login">Login</a></p>
|
||||||
<p><a href="/login">← Home</a></p>
|
<p><a href="/login">← Home</a></p>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:97
|
//line views/auth.qtpl:106
|
||||||
}
|
}
|
||||||
//line views/auth.qtpl:97
|
//line views/auth.qtpl:106
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) {
|
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) {
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
StreamLogoutHTML(qw422016, can)
|
StreamLogoutHTML(qw422016, can)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
func LogoutHTML(can bool) string {
|
func LogoutHTML(can bool) string {
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
WriteLogoutHTML(qb422016, can)
|
WriteLogoutHTML(qb422016, can)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
return qs422016
|
return qs422016
|
||||||
//line views/auth.qtpl:101
|
//line views/auth.qtpl:110
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:103
|
//line views/auth.qtpl:112
|
||||||
func StreamLockHTML(qw422016 *qt422016.Writer) {
|
func StreamLockHTML(qw422016 *qt422016.Writer) {
|
||||||
//line views/auth.qtpl:103
|
//line views/auth.qtpl:112
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
@ -365,31 +430,31 @@ func StreamLockHTML(qw422016 *qt422016.Writer) {
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`)
|
`)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
func WriteLockHTML(qq422016 qtio422016.Writer) {
|
func WriteLockHTML(qq422016 qtio422016.Writer) {
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
StreamLockHTML(qw422016)
|
StreamLockHTML(qw422016)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
}
|
}
|
||||||
|
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
func LockHTML() string {
|
func LockHTML() string {
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
WriteLockHTML(qb422016)
|
WriteLockHTML(qb422016)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
return qs422016
|
return qs422016
|
||||||
//line views/auth.qtpl:133
|
//line views/auth.qtpl:142
|
||||||
}
|
}
|
||||||
|
67
web/auth.go
67
web/auth.go
@ -1,11 +1,13 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
||||||
"github.com/bouncepaw/mycorrhiza/user"
|
"github.com/bouncepaw/mycorrhiza/user"
|
||||||
@ -21,6 +23,9 @@ func initAuth() {
|
|||||||
if cfg.AllowRegistration {
|
if cfg.AllowRegistration {
|
||||||
http.HandleFunc("/register", handlerRegister)
|
http.HandleFunc("/register", handlerRegister)
|
||||||
}
|
}
|
||||||
|
if cfg.TelegramEnabled {
|
||||||
|
http.HandleFunc("/telegram-login", handlerTelegramLogin)
|
||||||
|
}
|
||||||
http.HandleFunc("/login", handlerLogin)
|
http.HandleFunc("/login", handlerLogin)
|
||||||
http.HandleFunc("/login-data", handlerLoginData)
|
http.HandleFunc("/login-data", handlerLoginData)
|
||||||
http.HandleFunc("/logout", handlerLogout)
|
http.HandleFunc("/logout", handlerLogout)
|
||||||
@ -118,6 +123,68 @@ func handlerLogin(w http.ResponseWriter, rq *http.Request) {
|
|||||||
w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser())))
|
w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
|
||||||
|
// Note there is no lock here.
|
||||||
|
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
|
||||||
|
rq.ParseForm()
|
||||||
|
var (
|
||||||
|
values = rq.URL.Query()
|
||||||
|
username = strings.ToLower(values.Get("username"))
|
||||||
|
seemsValid = user.TelegramAuthParamsAreValid(values)
|
||||||
|
err = user.Register(
|
||||||
|
username,
|
||||||
|
"", // Password matters not
|
||||||
|
"telegram",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if user.HasUsername(username) && user.UserByName(username).Group == "telegram" {
|
||||||
|
// Problems is something we put blankets on.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !seemsValid {
|
||||||
|
err = errors.New("Wrong parameters")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to register ‘%s’ using Telegram: %s", username, err.Error())
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
fmt.Fprint(
|
||||||
|
w,
|
||||||
|
views.BaseHTML(
|
||||||
|
"Error",
|
||||||
|
fmt.Sprintf(
|
||||||
|
`<main class="main-width"><p>Could not authorize using Telegram.</p><p>%s</p><p><a href="/login">Go to the login page<a></p></main>`,
|
||||||
|
err.Error(),
|
||||||
|
),
|
||||||
|
user.FromRequest(rq),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
errmsg := user.LoginDataHTTP(w, rq, username, "")
|
||||||
|
if errmsg != "" {
|
||||||
|
log.Printf("Failed to login ‘%s’ using Telegram: %s", username, err.Error())
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
fmt.Fprint(
|
||||||
|
w,
|
||||||
|
views.BaseHTML(
|
||||||
|
"Error",
|
||||||
|
fmt.Sprintf(
|
||||||
|
`<main class="main-width"><p>Could not authorize using Telegram.</p><p>%s</p><p><a href="/login">Go to the login page<a></p></main>`,
|
||||||
|
err.Error(),
|
||||||
|
),
|
||||||
|
user.FromRequest(rq),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Authorize ‘%s’ from Telegram", username)
|
||||||
|
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
// handlerLoginData logs the user in.
|
// handlerLoginData logs the user in.
|
||||||
//
|
//
|
||||||
// TODO: merge into handlerLogin as POST method.
|
// TODO: merge into handlerLogin as POST method.
|
||||||
|
Loading…
Reference in New Issue
Block a user