<repo_name>kalelc/go-rails-cook<file_sep>/go.mod
module github.com/kalelc/go-rails-cook

go 1.13

require golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7
<file_sep>/decrypt_test.go
package railscook

import (
	"testing"
)

func TestRails5CookieDecrypt(t *testing.T) {
	value := "<KEY>
	secret := "836fa3665997a860728bcb9e9a1e704d427cfc920e79d847d79c8a9a907b9e965defa4154b2b86bdec6930adbe33f21364523a6f6ce363865724549fdfc08553"
	salt := "<KEY>"

	sessionID := "05fff49bbc0f9e6e8101e4e81b947ebe"

	cookie := Cookie{Value: value, SecretKeyBase: secret, Salt: salt}
	cookie.Decrypt()

	if cookie.Content.SessionID != sessionID {
		t.Errorf("session_id in cookie doesn't match: got %v want %v", cookie.Content.SessionID, sessionID)
	}
}
<file_sep>/README.md
# go-rails-cook

[![Go Report Card](https://goreportcard.com/badge/github.com/kalelc/go-rails-cookie)](https://goreportcard.com/report/github.com/kalelc/go-rails-cookie) [![CircleCI](https://circleci.com/gh/kalelc/go-rails-cook/tree/master.svg?style=svg)](https://circleci.com/gh/kalelc/go-rails-cook/tree/master)


`go-rails-cook` is a project to works with Rails' Cookies. It allows decrypting(until this moment) Cookies created with Rails 5 and higher.

## Requirement

- Cookie Content
- Secret Key
- Salt


## Examples

#### Decrypt

```
railscook "github.com/kalelc/go-rails-cook"

value := "<KEY>
secret := "836fa3665997a860728bcb9e9a1e704d427cfc920e79d847d79c8a9a907b9e965defa4154b2b86bdec6930adbe33f21364523a6f6ce363865724549fdfc08553"
salt := "<KEY>"

cookie := railscook.Cookie{Value: value, SecretKeyBase: secret, Salt: salt}
cookie.decrypt()

fmt.Printf("%+v", cookie.Content)

&{SessionID:05fff49bbc0f9e6e8101e4e81b947ebe Csrf:}

```
<file_sep>/decrypt.go
package railscook

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"strings"

	"golang.org/x/crypto/pbkdf2"
)

const (
	keyIterNum = 1000
	keySize    = 32
)

func (cookie *Cookie) Decrypt() {
	cookie.Decode()

	key := cookie.GenerateKey()
	block, err := aes.NewCipher(key)

	if err != nil {
		panic(err.Error())
	}

	aesgcm, err := cipher.NewGCM(block)

	if err != nil {
		panic(err.Error())
	}

	plaintext, err := aesgcm.Open(nil, cookie.Iv, cookie.Data, nil)

	if err != nil {
		panic(err.Error())
	}

	if err := json.Unmarshal(plaintext, &cookie.Content); err != nil {
		panic(err)
	}
}

func (cookie *Cookie) Decode() {

	encryptedData := strings.Split(cookie.Value, "--")

	data, _ := base64.StdEncoding.DecodeString(encryptedData[0])
	iv, _ := base64.StdEncoding.DecodeString(encryptedData[1])
	authTag, _ := base64.StdEncoding.DecodeString(encryptedData[2])

	cookie.Data = []byte(append(data, authTag...))
	cookie.Iv = []byte(iv)
}

func (cookie *Cookie) GenerateKey() []byte {
	return pbkdf2.Key([]byte(cookie.SecretKeyBase), []byte(cookie.Salt), keyIterNum, keySize, sha1.New)
}
<file_sep>/cookie.go
package railscook

import "encoding/json"

type Cookie struct {
	Value         string
	Data          []byte
	Iv            []byte
	SecretKeyBase string
	Salt          string
	Content       *Content
}

type Content struct {
	SessionID   string          `json:"session_id"`
	Csrf        string          `json:"_csrf_token"`
	UserSession json.RawMessage `json:"warden.user.user.session"`
}
