1
0
Fork 0
mirror of https://github.com/mautrix/discord.git synced 2026-05-15 05:36:54 -04:00
mautrix-discord/pkg/discordauth/personality.go
Skip R 26546297bb auth: implement MFA for TOTP, SMS, and backup codes
* create ChallengeHandler interface that clients must implement
* support asking discord to send the user's phone an SMS code
2026-03-27 21:07:59 -07:00

110 lines
4.2 KiB
Go

// mautrix-discord - A Matrix-Discord puppeting bridge.
// Copyright (C) 2026 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package discordauth
import (
"encoding"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"github.com/bwmarrin/discordgo"
)
const HeaderDiscordLocale = "x-discord-locale"
const HeaderDiscordTimezone = "x-discord-timezone"
const HeaderSuperProperties = "x-super-properties"
const HeaderContextProperties = "x-context-properties"
const HeaderFingerprint = "x-fingerprint"
const HeaderDebugOptions = "x-debug-options"
const DefaultDebugOptions = "bugReporterEnabled"
// Personality encapsulates some settings that clients are likely to want to
// customize. These values are sent in nearly every HTTP request to Discord.
type Personality struct {
UserAgent string
Locale string // `x-discord-locale`
TimeZone string // `x-discord-timezone`
DebugOptions string // `x-debug-options`
SuperProperties SuperProperties // `x-super-properties` (base64)
ExtraHeaders map[string]string
}
func (p *Personality) Headers() (http.Header, error) {
superProps, err := p.SuperProperties.MarshalText()
if err != nil {
return nil, fmt.Errorf("failed to marshal super properties: %w", err)
}
header := make(http.Header)
header.Set("User-Agent", p.UserAgent)
header.Set(HeaderDiscordLocale, p.Locale)
header.Set(HeaderDiscordTimezone, p.TimeZone)
header.Set(HeaderSuperProperties, string(superProps))
for k, v := range p.ExtraHeaders {
header.Set(k, v)
}
return header, nil
}
// FIXME(skip): This is missing client_heartbeat_session_id... that's only
// relevant when you have a gateway connection, though (?)
type SuperProperties struct {
OS string `json:"os"`
Browser string `json:"browser"`
Device string `json:"device"`
SystemLocale string `json:"system_locale"`
HasClientMods bool `json:"has_client_mods"`
BrowserUserAgent string `json:"browser_user_agent"`
BrowserVersion string `json:"browser_version"`
OSVersion string `json:"os_version"`
Referrer string `json:"referrer"`
ReferringDomain string `json:"referring_domain"`
ReferrerCurrent string `json:"referrer_current"`
ReferringDomainCurrent string `json:"referring_domain_current"`
ReleaseChannel string `json:"release_channel"`
ClientBuildNumber int `json:"client_build_number"`
ClientEventSource *string `json:"client_event_source"`
ClientLaunchID string `json:"client_launch_id"`
LaunchSignature discordgo.LaunchSignature `json:"launch_signature"`
ClientAppState string `json:"client_app_state"`
}
var _ encoding.TextMarshaler = (*SuperProperties)(nil)
func (sp *SuperProperties) MarshalText() ([]byte, error) {
// TODO(skip): Little bit of weird looking indirection here so we don't
// recurse infinitely. Should probably just remove this, then.
type superProperties SuperProperties
spJson, err := json.Marshal((*superProperties)(sp))
if err != nil {
return nil, err
}
// Avoid the string() call that EncodeToString incurs.
encoding := base64.StdEncoding
buf := make([]byte, encoding.EncodedLen(len(spJson)))
encoding.Encode(buf, spJson)
return buf, nil
}