mirror of
https://github.com/muun/recovery.git
synced 2025-11-11 06:20:16 -05:00
Release 2.0.0
This commit is contained in:
95
vendor/github.com/muun/libwallet/emergencykit/emergencykit.go
generated
vendored
95
vendor/github.com/muun/libwallet/emergencykit/emergencykit.go
generated
vendored
@@ -2,8 +2,9 @@ package emergencykit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
@@ -11,7 +12,9 @@ import (
|
||||
// Input struct to fill the PDF
|
||||
type Input struct {
|
||||
FirstEncryptedKey string
|
||||
FirstFingerprint string
|
||||
SecondEncryptedKey string
|
||||
SecondFingerprint string
|
||||
}
|
||||
|
||||
// Output with the html as string and the verification code
|
||||
@@ -20,24 +23,57 @@ type Output struct {
|
||||
VerificationCode string
|
||||
}
|
||||
|
||||
var spanishMonthNames = []string{
|
||||
"Enero",
|
||||
"Febrero",
|
||||
"Marzo",
|
||||
"Abril",
|
||||
"Mayo",
|
||||
"Junio",
|
||||
"Julio",
|
||||
"Agosto",
|
||||
"Septiembre",
|
||||
"Octubre",
|
||||
"Noviembre",
|
||||
"Diciembre",
|
||||
}
|
||||
|
||||
// GenerateHTML returns the translated emergency kit html as a string along with the verification code.
|
||||
func GenerateHTML(params *Input, lang string) (*Output, error) {
|
||||
verificationCode := randomCode(6)
|
||||
verificationCode := generateDeterministicCode(params)
|
||||
|
||||
// Render output descriptors:
|
||||
var descriptors string
|
||||
|
||||
if params.hasFingerprints() {
|
||||
descriptors = GetDescriptorsHTML(&DescriptorsData{
|
||||
FirstFingerprint: params.FirstFingerprint,
|
||||
SecondFingerprint: params.SecondFingerprint,
|
||||
})
|
||||
}
|
||||
|
||||
// Render page body:
|
||||
content, err := render("EmergencyKitContent", lang, &contentData{
|
||||
// Externally provided:
|
||||
FirstEncryptedKey: params.FirstEncryptedKey,
|
||||
SecondEncryptedKey: params.SecondEncryptedKey,
|
||||
VerificationCode: verificationCode,
|
||||
// Careful: do not change these format values. See this doc for more info: https://golang.org/pkg/time/#pkg-constants
|
||||
CurrentDate: time.Now().Format("2006/01/02"), // Format date to YYYY/MM/DD
|
||||
|
||||
// Computed by us:
|
||||
VerificationCode: verificationCode,
|
||||
CurrentDate: formatDate(time.Now(), lang),
|
||||
Descriptors: descriptors,
|
||||
|
||||
// Template pieces separated for reuse:
|
||||
IconHelp: iconHelp,
|
||||
IconPadlock: iconPadlock,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to render EmergencyKitContent template: %w", err)
|
||||
}
|
||||
|
||||
// Render complete HTML page:
|
||||
page, err := render("EmergencyKitPage", lang, &pageData{
|
||||
Css: css,
|
||||
Logo: logo,
|
||||
Content: content,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -50,17 +86,40 @@ func GenerateHTML(params *Input, lang string) (*Output, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func randomCode(length int) string {
|
||||
result := make([]byte, length)
|
||||
_, err := rand.Read(result)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func formatDate(t time.Time, lang string) string {
|
||||
if lang == "en" {
|
||||
return t.Format("January 2, 2006")
|
||||
|
||||
} else {
|
||||
// Golang has no i18n facilities, so we do our own formatting.
|
||||
year, month, day := t.Date()
|
||||
monthName := spanishMonthNames[month-1]
|
||||
|
||||
return fmt.Sprintf("%d de %s, %d", day, monthName, year)
|
||||
}
|
||||
charset := "0123456789"
|
||||
for i := 0; i < length; i++ {
|
||||
result[i] = charset[int(result[i])%len(charset)]
|
||||
}
|
||||
|
||||
func generateDeterministicCode(params *Input) string {
|
||||
// NOTE:
|
||||
// This function creates a stable verification code given the inputs to render the Emergency Kit. For now, the
|
||||
// implementation relies exclusively on the SecondEncryptedKey, which is the Muun key. This is obviously not ideal,
|
||||
// since we're both dropping part of the input and introducing the assumption that the Muun key will always be
|
||||
// rendered second -- but it compensates for a problem with one of our clients that causes the user key serialization
|
||||
// to be recreated each time the kit is rendered (making this deterministic approach useless).
|
||||
|
||||
// Create a deterministic serialization of the input:
|
||||
inputMaterial := params.SecondEncryptedKey
|
||||
|
||||
// Compute a cryptographically secure hash of the material (critical, these are keys):
|
||||
inputHash := sha256.Sum256([]byte(inputMaterial))
|
||||
|
||||
// Extract a verification code from the hash (doesn't matter if we discard bytes):
|
||||
var code string
|
||||
for _, b := range inputHash[:6] {
|
||||
code += strconv.Itoa(int(b) % 10)
|
||||
}
|
||||
return string(result)
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
func render(name, language string, data interface{}) (string, error) {
|
||||
@@ -80,12 +139,18 @@ func getContent(name string, language string) string {
|
||||
switch name {
|
||||
case "EmergencyKitPage":
|
||||
return page
|
||||
|
||||
case "EmergencyKitContent":
|
||||
if language == "es" {
|
||||
return contentES
|
||||
}
|
||||
return contentEN
|
||||
|
||||
default:
|
||||
panic("could not find template with name: " + name)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Input) hasFingerprints() bool {
|
||||
return i.FirstFingerprint != "" && i.SecondFingerprint != ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user