Publish HTML quickly. https://html.house
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

113 lines
2.4 KiB

  1. package htmlhouse
  2. import (
  3. "crypto/rsa"
  4. "fmt"
  5. jwt "github.com/dgrijalva/jwt-go"
  6. "github.com/juju/errgo"
  7. "io/ioutil"
  8. "net/http"
  9. )
  10. const (
  11. tokenHeader = "Authorization"
  12. )
  13. type sessionManager interface {
  14. readToken(*http.Request) (string, error)
  15. createToken(string) (string, error)
  16. writeToken(http.ResponseWriter, string) error
  17. }
  18. // Basic user session info
  19. type sessionInfo struct {
  20. ID string `json:"id"`
  21. }
  22. func newSessionInfo(houseID string) *sessionInfo {
  23. return &sessionInfo{houseID}
  24. }
  25. func newSessionManager(cfg *config) (sessionManager, error) {
  26. mgr := &defaultSessionManager{}
  27. // Read and parse private key
  28. signBytes, err := ioutil.ReadFile(cfg.PrivateKey)
  29. if err != nil {
  30. return mgr, errgo.Mask(err)
  31. }
  32. mgr.signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
  33. if err != nil {
  34. return mgr, errgo.Mask(err)
  35. }
  36. // Read and parse public key
  37. verifyBytes, err := ioutil.ReadFile(cfg.PublicKey)
  38. if err != nil {
  39. return mgr, errgo.Mask(err)
  40. }
  41. mgr.verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
  42. if err != nil {
  43. return mgr, errgo.Mask(err)
  44. }
  45. return mgr, nil
  46. }
  47. type defaultSessionManager struct {
  48. verifyKey *rsa.PublicKey
  49. signKey *rsa.PrivateKey
  50. }
  51. func (m *defaultSessionManager) readToken(r *http.Request) (string, error) {
  52. tokenString := r.Header.Get(tokenHeader)
  53. if tokenString == "" {
  54. return "", nil
  55. }
  56. token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  57. if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
  58. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  59. }
  60. return m.verifyKey, nil
  61. })
  62. switch err.(type) {
  63. case nil:
  64. if !token.Valid {
  65. return "", nil
  66. }
  67. claims := token.Claims.(jwt.MapClaims)
  68. houseID := claims["houseID"].(string)
  69. return houseID, nil
  70. case *jwt.ValidationError:
  71. return "", nil
  72. default:
  73. return "", errgo.Mask(err)
  74. }
  75. }
  76. func (m *defaultSessionManager) createToken(houseID string) (string, error) {
  77. token := jwt.New(jwt.SigningMethodRS512)
  78. claims := token.Claims.(jwt.MapClaims)
  79. claims["houseID"] = houseID
  80. tokenString, err := token.SignedString(m.signKey)
  81. if err != nil {
  82. return tokenString, errgo.Mask(err)
  83. }
  84. return tokenString, nil
  85. }
  86. func (m *defaultSessionManager) writeToken(w http.ResponseWriter, houseID string) error {
  87. tokenString, err := m.createToken(houseID)
  88. if err != nil {
  89. return err
  90. }
  91. w.Header().Set(tokenHeader, tokenString)
  92. return nil
  93. }