signup.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package libamuse
  2. import (
  3. "notabug.org/apiote/amuse/accounts"
  4. "bytes"
  5. "encoding/base32"
  6. "encoding/base64"
  7. "errors"
  8. "image"
  9. "strings"
  10. "github.com/chai2010/webp"
  11. "github.com/pquerna/otp"
  12. "github.com/pquerna/otp/totp"
  13. "notabug.org/apiote/gott"
  14. )
  15. func createSecret(args ...interface{}) (interface{}, error) {
  16. var (
  17. err error
  18. secretB []byte
  19. )
  20. result := args[1].(*Result)
  21. secret := args[4].(string)
  22. host := args[6].(string)
  23. if len(secret) > 0 {
  24. secretB, err = base32.StdEncoding.DecodeString(secret)
  25. }
  26. opts := totp.GenerateOpts{
  27. Issuer: host,
  28. AccountName: "nearly_headless_nick@" + host,
  29. Secret: secretB,
  30. }
  31. key, err := totp.Generate(opts)
  32. result.result = key
  33. return gott.Tuple(args), err
  34. }
  35. func createImage(args ...interface{}) (interface{}, error) {
  36. result := args[1].(*Result)
  37. secret := result.result.(*otp.Key)
  38. image, err := secret.Image(256, 256)
  39. result.result2 = image
  40. return gott.Tuple(args), err
  41. }
  42. func encodeWebp(args ...interface{}) (interface{}, error) {
  43. result := args[1].(*Result)
  44. image := result.result2.(image.Image)
  45. var buf bytes.Buffer
  46. err := webp.Encode(&buf, image, &webp.Options{Lossless: true})
  47. data := "data:image/webp;base64,"
  48. data += base64.StdEncoding.EncodeToString(buf.Bytes())
  49. result.result2 = data
  50. return gott.Tuple(args), err
  51. }
  52. func renderSignup(args ...interface{}) interface{} {
  53. result := args[1].(*Result)
  54. secret := result.result.(*otp.Key)
  55. qr := result.result2.(string)
  56. sfaEnabled := args[3].(bool)
  57. username := args[5].(string)
  58. var authError error
  59. if args[2] != nil {
  60. authError = args[2].(error)
  61. }
  62. result.page = result.renderer.RenderSignup(result.languages, authError, secret, sfaEnabled, username, qr)
  63. return gott.Tuple(args)
  64. }
  65. func ShowSignup(acceptLanguages, mimetype string, err error, sfaEnabled bool, sfaSecret, username, host string) (string, error) {
  66. r, err := gott.
  67. NewResult(gott.Tuple{&RequestData{language: acceptLanguages, mimetype: mimetype}, &Result{}, err, sfaEnabled, sfaSecret, username, host}).
  68. Bind(parseLanguage).
  69. Bind(createSecret).
  70. Bind(createImage).
  71. Bind(encodeWebp).
  72. Bind(createRenderer).
  73. Map(renderSignup).
  74. Finish()
  75. if err != nil {
  76. return "", err
  77. } else {
  78. return r.(gott.Tuple)[1].(*Result).page, nil
  79. }
  80. }
  81. func DoSignup(username, password, passwordConfirm string, sfaEnabled bool, sfaSecret, sfa string) (string, error) {
  82. if password != passwordConfirm {
  83. return "", accounts.AuthError{
  84. Err: errors.New("passwords_dont_match"),
  85. }
  86. }
  87. if sfaEnabled {
  88. if sfa == "" {
  89. return "", accounts.AuthError{
  90. Err: errors.New("sfa_not_confirmed"),
  91. }
  92. }
  93. sfa = strings.ReplaceAll(sfa, " ", "")
  94. if !totp.Validate(sfa, sfaSecret) {
  95. return "", accounts.AuthError{
  96. Err: errors.New("sfa_code_not_correct"),
  97. }
  98. }
  99. }
  100. if username == "" || password == "" || sfaSecret == "" {
  101. return "", accounts.AuthError{
  102. Err: errors.New("required_info_missing"),
  103. }
  104. }
  105. if !sfaEnabled {
  106. sfaSecret = ""
  107. }
  108. return accounts.Signup(username, password, sfaSecret)
  109. }
  110. func renderSignedup(args ...interface{}) interface{} {
  111. result := args[1].(*Result)
  112. recoveryCodes := args[2].(string)
  113. codes := []string{}
  114. if recoveryCodes != "" {
  115. codes = strings.Split(recoveryCodes, ",")
  116. }
  117. result.page = result.renderer.RenderSignedup(result.languages, codes)
  118. return gott.Tuple(args)
  119. }
  120. func ShowSignedup(acceptLanguages, mimetype, recoveryCodes string) (string, error) {
  121. r, err := gott.
  122. NewResult(gott.Tuple{&RequestData{language: acceptLanguages, mimetype: mimetype}, &Result{}, recoveryCodes}).
  123. Bind(parseLanguage).
  124. Bind(createRenderer).
  125. Map(renderSignedup).
  126. Finish()
  127. if err != nil {
  128. return "", err
  129. } else {
  130. return r.(gott.Tuple)[1].(*Result).page, nil
  131. }
  132. }