Commit e077803e authored by Yifan Gu's avatar Yifan Gu

Merge pull request #105 from yifan-gu/tests

refresh: bcrypt raw bytes rather than base64 encoded string.
parents ff71593c 44c6cb44
-- +migrate Up
CREATE TABLE refresh_token (
id bigint NOT NULL,
payload_hash text,
payload_hash bytea,
user_id text,
client_id text
);
......
......@@ -155,7 +155,7 @@ func dbMigrations0004_session_nonceSql() (*asset, error) {
return a, nil
}
var _dbMigrations0005_refresh_token_createSql = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x90\x51\x4f\xc2\x30\x10\xc7\xdf\xf7\x29\xee\x0d\x88\x62\xc2\x2b\x3e\x95\xed\x0c\x8b\x5d\xa7\x5d\x2b\xf2\xb4\x54\x56\x59\xc3\x1c\x73\xad\x46\xbe\xbd\x65\x13\x08\xc4\x68\xdf\xfa\xbb\xfb\xdf\x2f\x77\xe3\x31\x5c\xbd\x99\x75\xab\x9c\x06\xd9\x04\x21\x47\x22\x10\x04\x99\x51\x84\x56\xbf\xb6\xda\x96\xb9\xdb\x6e\x74\x0d\xc3\x00\xfc\x33\x05\xbc\x98\xb5\xa9\x1d\xb0\x54\x00\x93\x94\x5e\x77\xbc\x51\xbb\x6a\xab\x8a\xbc\x54\xb6\x04\xa7\xbf\x5c\x8f\x3f\xac\x6e\x73\x9f\x39\x91\x55\x65\x74\xed\x0e\x2c\x18\xdd\x06\x07\x69\x86\x8f\x12\x59\x78\xe1\xf5\x9d\xb9\xd5\xef\x5d\x36\x13\x84\x0b\x58\xc4\x62\x0e\x93\x0e\xc4\xcc\x67\x13\x64\x02\x66\xcb\x1f\xc4\x52\x48\x62\xf6\x44\xa8\xc4\xe3\x9f\x3c\x9f\xfe\x21\x09\xe7\x08\x13\xaf\x25\x54\x20\xff\xdb\x0a\xe9\x82\x61\xb4\x1f\x7e\x56\xbd\x31\xc5\x31\xdf\x9f\x2a\x65\xf4\xa2\x07\xfa\x72\x98\x52\x99\xb0\xfd\xd9\x32\x14\x10\xe1\x1d\x91\x54\x40\xed\x57\xff\x54\xd5\x70\xf0\x9b\x74\x30\x9d\xb6\x7a\xbd\xaa\x94\xb5\xa3\x7f\x35\xdd\x4e\x24\x8a\xbc\x88\x65\x82\x93\xd8\xdf\xe2\x7c\x68\xb3\xd1\x3b\x78\xe0\x71\x42\xf8\x12\xee\x71\x09\x43\x53\xf8\xb9\xdf\x01\x00\x00\xff\xff\xff\xeb\x3d\xc4\xf9\x01\x00\x00")
var _dbMigrations0005_refresh_token_createSql = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x90\x51\x4f\xc2\x30\x10\xc7\xdf\xf7\x29\xee\x0d\x88\x62\xc2\x2b\x3e\x95\xed\x0c\x8b\x5d\xa7\x5d\x2b\xf2\xb4\x14\x56\xa1\x61\x8e\xb9\x56\xe3\xbe\xbd\x65\x13\x0c\xc4\x68\xdf\xfa\xbb\xfb\xdf\x2f\x77\xe3\x31\x5c\xbd\x9a\x4d\xa3\x9c\x06\x59\x07\x21\x47\x22\x10\x04\x99\x51\x84\x46\xbf\x34\xda\x6e\x73\xb7\xdf\xe9\x0a\x86\x01\xf8\x67\x0a\x58\x99\x8d\xa9\x1c\xb0\x54\x00\x93\x94\x5e\x77\xbc\x56\x6d\xb9\x57\x45\xbe\x55\x76\x0b\xab\xd6\x69\xd5\xf3\x77\xab\x9b\xdc\x87\x9c\xfe\x74\x3d\x59\x97\x46\x57\xee\xc8\x82\xd1\x6d\x70\xb4\x66\xf8\x28\x91\x85\x17\x62\xdf\x99\x5b\xfd\xd6\x65\x33\x41\xb8\x80\x45\x2c\xe6\x30\xe9\x40\xcc\x7c\x36\x41\x26\x60\xb6\xfc\x46\x2c\x85\x24\x66\x4f\x84\x4a\x3c\xfd\xc9\xf3\xcf\x3f\x24\xe1\x1c\x61\xe2\xb5\x84\x0a\xe4\x7f\x5b\x21\x5d\x30\x8c\x0e\xc3\xcf\xaa\x37\xa6\x38\xe5\xfb\x5b\xa5\x8c\x5e\xf4\x40\x5f\x0e\x53\x2a\x13\x76\xb8\x5b\x86\x02\x22\xbc\x23\x92\x0a\xa8\xfc\xea\x1f\xaa\x1c\x0e\x7e\x93\x0e\xa6\xd3\x46\x6f\xd6\xa5\xb2\x76\xf4\xaf\xa6\xdb\x89\x44\x91\x17\xb1\x4c\x70\x12\xfb\x5b\x9c\x0f\xad\x77\xba\x85\x07\x1e\x27\x84\x2f\xe1\x1e\x97\x30\x34\x85\x9f\xfb\x15\x00\x00\xff\xff\xc4\xcc\xa8\xfd\xfa\x01\x00\x00")
func dbMigrations0005_refresh_token_createSqlBytes() ([]byte, error) {
return bindataRead(
......@@ -170,7 +170,7 @@ func dbMigrations0005_refresh_token_createSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "db/migrations/0005_refresh_token_create.sql", size: 505, mode: os.FileMode(436), modTime: time.Unix(1, 0)}
info := bindataFileInfo{name: "db/migrations/0005_refresh_token_create.sql", size: 506, mode: os.FileMode(436), modTime: time.Unix(1, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
......@@ -215,7 +215,7 @@ func dbMigrations0007_session_scopeSql() (*asset, error) {
return a, nil
}
var _dbMigrationsAssetsGo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x99\xdf\x6f\xdb\x46\x12\xc7\x9f\xad\xbf\x82\x35\xd0\x42\x3e\xf8\x64\xfe\x14\x45\x03\x7d\x69\x93\x03\xf2\xd0\x14\xb8\xe6\x9e\xce\x07\x61\x49\x2e\x5d\xa2\xb2\xe4\x88\x72\xcf\x49\x90\xff\xfd\xe6\xb3\x33\xb2\x9d\x58\xb2\x13\xe7\x82\xa0\x0f\x8c\xc5\xe5\xec\xec\xfc\x9e\xd9\x6f\x4e\x4e\xa2\x9f\x57\xad\x8f\xce\xfd\xd2\xaf\xdd\xc6\xb7\x51\xfd\x26\x3a\x5f\xfd\xbd\xee\x97\xad\xdb\xb8\xc9\x48\x08\x86\xd5\xd5\xba\xf1\xc3\x29\xbf\xdb\xfa\xe4\xa2\x3f\x17\xca\x7e\xb5\x1c\x4e\xe2\x38\x4e\xe6\xfd\xb2\xdf\xf4\x6e\x31\xbf\x59\x9f\x0c\xaf\x17\x3b\x69\xd3\x79\xeb\xaf\xe7\xae\xbd\xe8\xf7\xd3\x64\xf3\xab\xc1\xaf\xe7\xcd\xda\x23\xcd\xdc\x6d\xf6\x52\xe6\xf3\xc1\x0f\x83\xbc\xcd\x97\xab\x65\xe3\xf7\xd2\x15\xf3\xb5\xef\xd6\x7e\xf8\x7d\xbe\x59\xfd\xe1\x97\xc6\x7a\x2f\xf9\x54\x05\xf0\x17\xae\x5f\xcc\xaf\x96\xfd\xeb\xab\xfd\xb4\xe5\x8d\x08\x43\xb3\xba\xdc\x43\xe7\x86\xc1\x6f\x86\xc9\xf9\x8a\x4f\xcf\x7e\x8d\x5e\xfe\xfa\x2a\x7a\xfe\xec\xc5\xab\xef\x46\xa3\x4b\xd7\xfc\xe1\xce\x7d\x74\x4b\x3d\x1a\xf5\x17\x97\xab\xf5\x26\x1a\x8f\x0e\x0e\xeb\x37\x1b\x3f\x1c\xca\x8f\x66\x75\x71\x29\x1a\x0c\x27\xe7\x6f\xfb\x4b\x16\xba\x8b\x0d\x7f\xfa\x15\xff\x0e\x9b\x75\xbf\x3c\x0f\x84\xab\xf0\xef\xa6\xbf\xf0\xfa\xf9\xa4\x5f\x5d\x6d\xfa\x05\x2f\x97\x6e\xf3\xfb\x49\xd7\x2f\x3c\x3f\x0e\x47\x47\xa3\x51\x77\xb5\x6c\x22\x73\xf4\x3f\xbd\x6b\xc7\xfc\x88\xfe\xfd\x1f\x8e\x3d\x8e\x96\xee\xc2\x47\xca\xfa\x28\x1a\x6f\x57\xfd\x7a\xbd\x5a\x1f\x45\xef\x46\x07\xe7\x6f\xc3\x5b\x74\xfa\x63\x84\x54\x93\x97\xfe\xbf\x30\xf1\xeb\x71\x10\x9b\xf7\x9f\xae\xba\x4e\xde\x61\x7b\x74\x34\x3a\xe8\xbb\xb0\xe1\xbb\x1f\xa3\x65\xbf\x80\xc5\xc1\xda\x6f\xae\xd6\x4b\x5e\x8f\x23\x51\x69\xf2\x1c\xee\xdd\xf8\x10\x46\xd1\xf7\xaf\x4f\xa3\xef\xff\x3c\x54\x49\xc2\x59\xc2\xe3\xfd\x68\x74\xf0\xa7\x5b\x47\xf5\x55\x17\xe9\x39\x7a\xc8\xe8\x60\xae\xe2\xfc\x18\xf5\xab\xc9\xcf\xab\xcb\x37\xe3\x1f\x84\xe6\x58\x64\x93\x5d\xcd\xe2\xf9\x56\xd2\xc9\xcf\x8b\xd5\xe0\xc7\xa2\xfe\xff\x49\x1e\xd8\x28\xff\x3d\x8c\x84\x50\xe5\xb6\x45\x11\x6b\xf2\x13\xa2\x8f\x8f\x8e\xa1\x18\xc9\xb7\xcd\x9b\x4b\x1f\x85\x40\xc1\xe4\x57\xcd\x06\x2e\x41\x3f\xf3\x87\x1c\xb3\xec\x56\x51\xb4\x1a\x26\xff\x10\x1f\xbe\x90\x97\x9b\x7d\xe6\xc2\xed\xfa\x1d\x0e\x77\x7c\x38\x3a\x18\xfa\xb7\x3e\xea\x97\x9b\x69\x3e\x3a\xb8\x20\xe7\x8d\xd7\x2f\xf2\x3b\xac\xbc\x92\xb0\x89\x88\x9d\x09\xbf\x60\x1f\x22\x64\xdc\xf5\x1f\x1f\x71\x14\xbd\x14\xce\xe3\x23\xe3\xcd\x51\xa6\x5c\xd7\x4f\x38\x54\x36\xef\xdf\xfb\x9b\x08\x22\x7b\x83\x28\x1f\x6e\x45\xc4\x07\xb7\x22\xab\x6c\xbd\x23\xf9\x87\x0c\xd0\xeb\x31\x06\x28\x27\x3c\x6e\x14\xbd\xc7\xc1\xb4\xdf\xcf\xe4\xc5\xf0\xac\x5f\x0b\x8b\x7a\xb5\x5a\xdc\xdd\xed\x16\xc3\x23\x9a\xbf\x19\x54\x71\xbf\xee\x5c\xe3\xdf\xbd\xbf\xb3\xdb\x22\x81\xe0\x9e\xb7\xf5\x2f\x37\x15\x61\x77\x8d\xfd\xed\xf5\x42\x42\x5d\x63\x63\x7c\x78\x76\x9d\x74\x67\xd7\xb3\xfa\xec\x3a\x9e\xc9\x13\xdb\x53\x9d\x5d\x4f\xbd\xac\xdb\x5a\x27\x34\x55\x23\x4f\x76\x76\xdd\x40\xef\xce\xae\x5b\xd9\x93\xc9\xb7\x44\x9e\x66\x7a\x76\xed\x65\xbd\x94\x7d\xb1\x7c\xab\x12\xf9\x2e\xb4\x33\x59\x9f\xca\x53\xc9\x37\x27\x74\xae\x94\xf7\x56\xe8\xe4\xfb\x54\x1e\x27\x4f\x9d\x0b\xad\x7c\x2b\x0b\x7d\xcf\x84\x26\x63\x5d\xde\x53\xf8\x8a\x1c\x05\x32\xc8\xbe\x5c\x78\x26\xc2\x7f\x2a\xfc\xda\x52\xff\x16\xfc\x96\x73\x73\xa1\x4b\x84\x57\x23\xeb\x8d\x57\x99\xd8\x3f\x13\x5e\x33\x59\x2f\x44\x97\x56\xde\x3b\xd1\xc3\x23\x53\xad\xfb\x91\x2f\xf1\x6a\x87\x46\xce\x8c\x4b\x3d\x07\x79\xd0\x3d\x67\x8f\xe9\x03\x7d\xe6\xd5\x1e\xa9\xf0\xab\x38\x47\xe4\xc9\x53\xf9\x2d\x67\xe4\x9d\xea\x5a\xc3\x0f\xd9\x65\xbd\xab\xd4\xbe\x9d\xd0\x77\xb2\x56\xb7\x26\x27\xfa\x0a\xad\x97\xf3\x2a\x79\x3a\xa1\xcd\x65\x6d\xda\xa8\x1d\x3c\xb6\x90\xef\xb9\xf0\xcf\x90\x51\xde\x1b\x91\xa1\x90\xdf\x59\xa3\x74\x8d\xf0\xe9\x62\xd5\xbf\x92\xfd\xad\x53\xfb\xa3\x3b\x76\x44\x06\x74\x76\x85\xca\xee\x32\xb5\x2b\x7b\xb0\x4b\xdc\x98\x6d\xcc\x2e\xc8\x54\x6e\xfd\xd5\xa9\x1c\x31\xba\xa7\x7a\x76\x23\xb2\x37\x95\xae\x97\x46\x9f\xc7\x6a\xb3\x26\x35\x79\xe4\xbb\x6f\x35\x5e\xb0\x5d\x1d\xab\x8e\x71\xad\x71\xe3\x52\xf5\x1d\x3e\x47\x37\xd6\xe3\xa9\xc6\x46\x93\x68\x9c\x20\x17\x3a\x25\xf2\xb7\xc6\xe7\x99\xfa\x27\xc4\x06\x7b\xe5\xdc\x02\xbb\x39\xe5\x53\x0b\xcf\x54\xce\xae\x90\x9f\xb8\xad\x2c\x3e\x6b\x3d\x83\x38\xc6\xff\xb1\x7c\xf7\xb9\xfa\xaa\x26\x06\x0b\xd5\xbf\xcb\xf4\x3d\x4f\x54\x16\xe8\x90\x21\xc6\xe7\x7c\x2b\x95\x7f\xb0\xbf\xf9\x33\x11\x9a\x5a\xfe\xa6\xb1\xc6\x46\xdd\x29\x3d\xb2\x95\x42\xef\xe5\x3c\x1f\xab\xfd\xb1\x67\xd3\xe8\x1a\x39\x92\xb5\xea\x13\x72\x89\x78\x40\x26\xce\xc6\x86\xb3\xc6\xe4\x91\xf5\x59\xaa\x79\x88\xbf\x90\x1f\x7a\xf8\x63\x5b\x64\x08\xb6\xef\x34\x5f\x3a\xa1\x2b\x33\xe5\x93\x57\x6a\x93\xd8\xec\x85\x1f\x90\xa9\x90\xef\x69\xaa\xb6\x43\x2e\xe8\x39\x23\x17\x7e\x49\xad\x7c\x89\x3b\x62\x95\x1c\x49\xa9\x03\xb1\x7e\xc7\x8e\xae\xd2\x9c\x42\xef\xa2\xd1\xdc\xc1\xe7\xc9\x4c\xe3\x02\x9f\x95\x7c\x73\xaa\xef\xb4\x52\xf9\x1c\xf1\x28\x6b\xc5\xd6\xf7\x99\xf2\x22\x66\x1b\xe1\x9f\x96\x6a\x73\xe2\x93\xda\x43\x3e\x3a\xe2\x92\x5a\xd1\x6a\x7e\x40\x83\x2d\xf0\x0f\x71\x51\x78\x95\x21\x6f\x35\xce\xa9\x11\x69\xa1\xf2\x12\x97\x41\xff\x4a\xcf\xc5\x06\xc4\x25\x79\x43\xbd\x21\x9e\xa0\x0f\xe7\x4c\xd5\x27\xc8\x12\xea\xa0\xac\xf9\x46\x63\xa7\x8c\x95\x3f\xf5\x0c\x9d\xdb\x56\x65\xe2\x37\x36\xcf\x4b\xb5\x9b\xe7\x5c\xe1\x3b\x95\xb3\x3a\xa7\x35\xa8\x20\xd6\xa0\x4b\x35\xc6\xf0\x1d\x3e\x87\x07\x6b\x29\x7c\x2b\xcd\x07\xea\x21\xfe\x26\x6f\x67\x56\x4f\xe1\x8f\x0f\x1c\x74\x53\xd5\xbb\x6e\xd4\x0e\xd8\x98\x78\xe5\x0c\x7c\x48\x5d\x46\x5f\xe2\xa4\xc3\xbe\x8d\xd6\x49\x6a\x98\xcf\x34\xfe\x4b\x6a\x56\xa7\x3a\x15\xc4\x3f\xbe\x92\xf5\x7a\xa6\xfe\xa5\x2e\x84\x5e\x50\x6a\x2d\xaf\x9d\xfa\x9c\xb8\x22\x8e\xb6\xbd\x81\xda\xc7\xe3\xbc\xd6\x39\x72\x88\x5a\x4e\x3d\x8a\x8b\x2d\xdd\xe1\x76\x4a\xfc\xa4\x86\x64\x43\xcd\xae\x61\x71\x3b\xfa\xdc\x19\x36\x65\x4a\xfa\xb4\x3e\x77\x2c\x94\x87\x9f\x7a\xef\x38\x14\xea\xa3\x9b\xd1\xe5\x93\xf8\x23\xf1\xdf\xc2\xec\x75\x57\xe2\x30\x7c\xdd\x4c\xb8\x9f\xa3\xff\x63\x83\xe5\xcd\x3c\x18\x26\x3a\x61\xfe\xd1\x98\xf0\x8e\x01\xea\x34\xfa\x0c\x95\x23\xe6\xa6\xd3\x28\xc9\x66\xb3\xe3\x88\x11\xe8\xf4\xee\x84\x34\xce\xb3\xe9\x51\x58\x67\xb0\x39\xd5\xc1\xe7\x5f\xcb\xfe\x7a\x9c\x1c\x47\xf1\x91\x4c\xb0\x0e\x29\x7e\x08\x26\x78\x17\xf4\x3e\x8d\x4c\x7d\x44\x3c\x8d\xc2\x9f\xf7\x37\x5e\x74\xc7\x0f\x0d\x2b\x77\x2e\x79\x4f\x1d\x52\x68\x54\xa1\x39\x14\xda\x18\xc2\x20\xd0\x6a\x80\xa7\xd6\x4c\xd3\x46\x0b\x24\x34\xf0\x23\x11\x29\xd4\x25\x09\x94\x2b\x5f\x12\x32\x6e\xb5\x60\x41\xc3\x7b\x99\x6b\x93\x2e\x2d\xf1\xf2\x99\xf1\xaf\x94\x3f\xe7\xa4\xb5\x36\x1f\x92\x9d\x35\x9a\x27\x85\x85\x44\xa7\x38\xd1\xa0\x68\xd0\x33\xd9\x97\xda\x13\x1a\xb6\xd7\x44\x63\xb8\x08\x43\x91\xd7\x46\x16\x5b\x12\x52\x88\x29\x98\x34\x1d\x86\x11\xce\x60\x8d\x24\x86\x37\x05\x2c\xb7\xe6\x8f\x6e\x9d\x3d\x99\xed\x9b\x19\x0d\x45\x9f\xa2\x59\x34\xb7\xcd\x1d\x19\x82\x3c\x89\x26\xf5\xf6\xcc\xe9\x4c\x8b\x08\x32\x33\xb0\xd0\x28\x0a\x1b\xc2\x28\x9e\x61\x70\xc3\x7e\x4e\x8b\x35\xfa\x51\xb0\xa0\xa5\x99\xd3\x04\x28\x4e\x9c\x11\xa7\xf7\x0b\x08\x32\xd5\xd6\x78\x43\xa1\xf7\x77\x7c\xbb\xb7\x80\x7c\x18\x24\x5f\x5c\x38\x3e\x64\xb7\xbb\x60\x7c\x04\x3e\x3c\x58\x28\x3e\xe4\xf7\x84\x02\xb1\x53\xbf\xaf\x56\x18\xee\xa9\xb6\x2d\x08\xe9\xf4\xdb\xd7\x83\x7b\x80\xce\x5f\xa5\x2a\xc0\x2b\xb5\x51\x99\xf7\x90\xad\x9d\xae\x71\x4d\x49\x8d\x07\xad\x98\xfd\x61\x6f\xa2\xef\x5c\x11\x68\xe1\x9c\xd7\x15\xfa\x14\x96\x71\x41\x4e\x6f\x99\x5e\x68\xe6\xe5\x36\xee\x72\xf5\xe0\x5c\xf8\xc0\x3b\x54\x27\x67\x95\xc9\xc6\xcf\xd4\xc6\x06\x6f\x57\x13\x32\x1d\x7d\x82\x1c\x76\x1d\x60\x7c\x6c\xe5\x49\x52\x1d\x83\xa8\x00\x64\xbe\x73\x56\x3d\xa6\x3a\xa6\x33\xb6\x55\x36\xbe\x27\xf1\xfd\xec\x4e\xad\x3a\x7a\xbb\xca\x70\xfd\x78\x3c\xbb\x77\xb9\xfc\x8b\x73\x7c\x17\xd3\xdd\x99\xbe\x13\x42\x7c\x30\xdf\x77\xf1\x7e\x42\xd6\x3f\xa0\xf7\x57\xcb\xfd\x3d\xca\x6e\x2b\x40\x92\x7c\xfb\x0a\xf0\x11\x50\xfb\x57\xc8\x7f\xe2\x7e\x9b\xe3\xe4\x6a\x38\xcb\x72\x90\x3c\xfe\xdc\x9c\x27\x87\x9b\xda\x26\x8a\x5a\x79\x73\x0e\x32\x84\xb3\x2a\xbd\x22\xf0\x7b\x9b\xdb\xa1\xdb\xe6\xf7\x73\x92\x2b\x20\x30\x02\xd7\x25\xec\xc6\x75\xe8\xf1\x9c\xbc\xef\x84\x2f\xce\xc8\xfb\x2c\x77\xe7\xe3\x0e\xa0\xfe\xc1\x6c\xbc\xcf\xf7\x09\xb9\xb8\x57\xdf\xaf\x96\x89\x3b\xd5\xb4\x3c\x9c\xc6\xdf\x3e\x0d\x77\xff\x3f\xc8\x53\xb3\x91\xcb\x70\x15\x6b\xf4\xd3\xb5\x00\x3d\x6e\x80\x44\x2e\xaf\x9d\x66\x03\xf3\x2d\xe0\x1f\x19\xc7\xfe\x69\xaa\xb4\x74\x31\xe6\x64\xe6\x52\x80\xa6\xd8\xc0\x10\x66\xc8\x30\x77\xda\x1c\x4e\x56\x32\xa3\x16\x06\x70\x01\xdc\x00\xe0\x00\x1e\x30\x97\x92\x35\x01\xa0\xf2\x7a\xf9\xe6\x22\x0b\x30\x80\xfc\x80\x1a\xcc\xbf\x41\x16\xa7\x17\xfe\xae\xd6\xf7\xd4\x32\x89\x8b\x35\x97\x74\x66\xe9\xda\x2e\xf3\x01\xc4\x34\x20\x85\x0b\x3b\x80\x08\x99\x98\x1a\x58\x00\xf8\x12\xba\x65\xae\xf4\x45\x72\x0b\xc0\x01\x20\xd5\x53\x05\xf1\xb8\xf0\xd7\x06\x62\x61\x3f\x2a\x06\x76\x40\xfe\x60\x47\x00\x8a\x4c\xa7\x00\x40\x81\x6a\xa6\x17\xf8\x70\x47\x68\x15\x74\x2b\xac\x02\x00\x0e\x00\x78\x01\x98\x20\x77\x6d\x53\x02\x3a\x01\x58\x38\x03\xe6\xc2\x7a\xae\x32\xc4\x36\xc3\x23\x13\xfa\xcd\x3a\x05\x23\x5d\x63\xf2\x64\x0a\x6a\x71\xbf\xa8\xac\xf2\x61\x3f\xe4\x0c\x3e\xf1\x5a\x51\x01\x86\x00\x3c\x02\xa8\x56\x2a\x20\x04\x28\x0c\x3f\x26\x8c\xc2\x40\x88\x00\x3a\x71\x3f\x6a\x4d\xef\x42\x41\x08\x7c\x19\xc0\xcf\x4c\xed\xc4\xb4\x51\x6c\xfd\x93\xea\x39\xe8\xc7\x5f\xd6\x02\xe8\x54\x2a\x3d\x80\x0c\x95\x30\x80\x54\xb5\x01\xbc\xf9\xed\x74\xc4\x7e\x2a\x6f\x8e\xae\xc6\xd3\x6f\xf5\x6a\xf4\x6f\x67\xf7\x22\xe2\x38\x80\x98\x33\xe5\x0d\x38\xca\x7d\x07\x7b\xa5\xdb\x2e\x53\xeb\x44\xe5\x2b\x03\xee\x0c\xdc\xe6\x5c\xee\x36\x85\x81\xbf\xc4\x0c\x00\x15\x7f\x5b\x03\x8c\x99\xe4\xb0\x1f\x9d\xc6\x19\x70\x47\xdc\xd1\x7d\xf0\x6d\x61\x77\xc8\xda\x80\x70\xe2\x0a\x10\x89\xbb\x16\xf1\x84\xfd\x12\x03\xaa\x90\x09\x60\x10\x3f\x00\xf4\x21\x1b\x6b\x01\x98\x8c\x15\x24\x02\xfc\xc6\x57\xe4\x5d\xb0\x39\x20\x98\x53\xf9\x98\xf4\x02\x40\x6a\x80\x1c\xc0\x51\x66\xc0\x55\xe8\x6c\xf9\x6d\xbc\x84\xbc\x2c\x54\x5f\xfc\xd0\x5a\xce\x30\x5d\x02\x10\x93\x43\xdc\xf1\x98\x28\x03\xa0\x66\xa0\x28\xdd\x0f\xd0\x1c\xa0\x31\x4c\x9a\xde\xba\x6b\x65\xf7\xcb\x4c\xbf\x85\x58\xe8\xec\x0e\xf9\x51\x37\xe3\x09\x00\x5b\x7b\x0b\x3c\xdf\xd2\xed\xeb\x66\x7b\x6b\xd9\x17\x37\xb5\xbd\x9c\x77\xf7\xb6\xfd\xff\xb9\xfc\x60\x8b\xdb\x7b\xca\x13\x3a\xdd\x63\xb6\x78\xb0\xe1\xfd\x2f\x00\x00\xff\xff\xfb\x08\x01\x0a\x00\x20\x00\x00")
var _dbMigrationsAssetsGo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x99\xdf\x6f\xdb\x46\x12\xc7\x9f\xad\xbf\x82\x35\xd0\x42\x3a\xf8\x64\x92\xe2\x2f\x19\xe8\x4b\xdb\x1c\x90\x87\xa6\xc0\x35\xf7\x74\x3e\x08\x4b\x72\xe9\x12\x95\x25\x47\x94\x7b\x4e\x82\xfc\xef\x37\x9f\x9d\x91\xeb\xc4\x92\x9d\x38\x17\x04\x7d\x60\x2c\x2e\x67\x67\xe7\xf7\xcc\x7e\x73\x7a\x1a\xfd\xb8\x6e\x7d\x74\xe1\x57\x7e\xe3\xb6\xbe\x8d\xea\xd7\xd1\xc5\xfa\xef\x75\xbf\x6a\xdd\xd6\x4d\x47\x42\x30\xac\xaf\x37\x8d\x1f\xce\xf8\xdd\xd6\xa7\x97\xfd\x85\x50\xf6\xeb\xd5\x70\x1a\xc7\x71\xb2\xe8\x57\xfd\xb6\x77\xcb\xc5\xed\xfa\x74\x78\xb5\xdc\x4b\x9b\x2e\x5a\x7f\xb3\x70\xed\x65\x7f\x98\x66\xb6\xb8\x1e\xfc\x66\xd1\x6c\x3c\xd2\x2c\xdc\xf6\x20\x65\xb6\x18\xfc\x30\xc8\xdb\x62\xb5\x5e\x35\xfe\x20\x5d\xbe\xd8\xf8\x6e\xe3\x87\xdf\x16\xdb\xf5\xef\x7e\x65\xac\x0f\x92\x17\x2a\x80\xbf\x74\xfd\x72\x71\xbd\xea\x5f\x5d\x1f\xa6\x2d\x6f\x45\x18\x9a\xf5\xd5\x01\x3a\x37\x0c\x7e\x3b\x4c\x2f\xd6\x7c\xfa\xe9\x97\xe8\xc5\x2f\x2f\xa3\x67\x3f\x3d\x7f\xf9\xcd\x68\x74\xe5\x9a\xdf\xdd\x85\x8f\xfe\xa4\x1e\x8d\xfa\xcb\xab\xf5\x66\x1b\x8d\x47\x47\xc7\xf5\xeb\xad\x1f\x8e\xe5\x47\xb3\xbe\xbc\x12\x0d\x86\xd3\x8b\x37\xfd\x15\x0b\xdd\xe5\x96\x3f\xfd\x9a\x7f\x87\xed\xa6\x5f\x5d\x04\xc2\x75\xf8\x77\xdb\x5f\x7a\xfd\x7c\xda\xaf\xaf\xb7\xfd\x92\x97\x2b\xb7\xfd\xed\xb4\xeb\x97\x9e\x1f\xc7\xa3\xc9\x68\xd4\x5d\xaf\x9a\xc8\x1c\xfd\x4f\xef\xda\x31\x3f\xa2\x7f\xff\x87\x63\x4f\xa2\x95\xbb\xf4\x91\xb2\x9e\x44\xe3\xdd\xaa\xdf\x6c\xd6\x9b\x49\xf4\x76\x74\x74\xf1\x26\xbc\x45\x67\xdf\x47\x48\x35\x7d\xe1\xff\x0b\x13\xbf\x19\x07\xb1\x79\xff\xe1\xba\xeb\xe4\x1d\xb6\x93\xc9\xe8\xa8\xef\xc2\x86\x6f\xbe\x8f\x56\xfd\x12\x16\x47\x1b\xbf\xbd\xde\xac\x78\x3d\x89\x44\xa5\xe9\x33\xb8\x77\xe3\x63\x18\x45\xdf\xbe\x3a\x8b\xbe\xfd\xe3\x58\x25\x09\x67\x09\x8f\x77\xa3\xd1\xd1\x1f\x6e\x13\xd5\xd7\x5d\xa4\xe7\xe8\x21\xa3\xa3\x85\x8a\xf3\x7d\xd4\xaf\xa7\x3f\xae\xaf\x5e\x8f\xbf\x13\x9a\x13\x91\x4d\x76\x35\xcb\x67\x3b\x49\xa7\x3f\x2e\xd7\x83\x1f\x8b\xfa\xff\x27\x79\x60\xa3\xfc\x0f\x30\x12\x42\x95\xdb\x16\x45\xac\xe9\x0f\x88\x3e\x9e\x9c\x40\x31\x92\x6f\xdb\xd7\x57\x3e\x0a\x81\x82\xc9\xaf\x9b\x2d\x5c\x82\x7e\xe6\x0f\x39\x66\xd5\xad\xa3\x68\x3d\x4c\xff\x21\x3e\x7c\x2e\x2f\xb7\xfb\xcc\x85\xbb\xf5\x3b\x1c\xee\xf8\x70\x74\x34\xf4\x6f\x7c\xd4\xaf\xb6\x45\x36\x3a\xba\x24\xe7\x8d\xd7\xcf\xf2\x3b\xac\xbc\x94\xb0\x89\x88\x9d\x29\xbf\x60\x1f\x22\x64\xdc\xf5\x1f\x1e\x31\x89\x5e\x08\xe7\xf1\xc4\x78\x73\x94\x29\xd7\xf5\x53\x0e\x95\xcd\x87\xf7\xfe\x2a\x82\xc8\xde\x20\xca\xfb\x5b\x11\xf1\xc1\xad\xc8\x2a\x5b\xef\x48\xfe\x3e\x03\xf4\x7a\x8c\x01\xca\x09\x8f\x5b\x45\xef\x71\x30\xed\x0f\x33\x79\x3e\xfc\xd4\x6f\x84\x45\xbd\x5e\x2f\xef\xee\x76\xcb\xe1\x11\xcd\x5f\x0f\xaa\xb8\xdf\x74\xae\xf1\x6f\xdf\xdd\xd9\x6d\x91\x40\x70\x2f\xda\xfa\xe7\xdb\x8a\xb0\xbf\xc6\xfe\xfa\x6a\x29\xa1\xae\xb1\x31\x3e\x3e\xbf\x49\xba\xf3\x9b\xaa\x3e\xbf\x89\x2b\x79\x62\x7b\xe6\xe7\x37\x85\x97\x75\x5b\xeb\x84\x66\xde\xc8\x33\x3b\xbf\x69\xa0\x77\xe7\x37\xad\xec\x99\xc9\xb7\x44\x9e\xa6\x38\xbf\xf1\xb2\x5e\xca\xbe\x58\xbe\xcd\x13\xf9\x2e\xb4\x95\xac\x17\xf2\xcc\xe5\x9b\x13\x3a\x57\xca\x7b\x2b\x74\xf2\xbd\x90\xc7\xc9\x53\x67\x42\x2b\xdf\xca\x5c\xdf\x67\x42\x33\x63\x5d\xde\x53\xf8\x8a\x1c\x39\x32\xc8\xbe\x4c\x78\x26\xc2\xbf\x10\x7e\x6d\xa9\x7f\x73\x7e\xcb\xb9\x99\xd0\x25\xc2\xab\x91\xf5\xc6\xab\x4c\xec\xaf\x84\x57\x25\xeb\xb9\xe8\xd2\xca\x7b\x27\x7a\x78\x64\xaa\x75\x3f\xf2\x25\x5e\xed\xd0\xc8\x99\x71\xa9\xe7\x20\x0f\xba\x67\xec\x31\x7d\xa0\x9f\x79\xb5\x47\x2a\xfc\xe6\x9c\x23\xf2\x64\xa9\xfc\x96\x33\xb2\x4e\x75\xad\xe1\x87\xec\xb2\xde\xcd\xd5\xbe\x9d\xd0\x77\xb2\x56\xb7\x26\x27\xfa\x0a\xad\x97\xf3\xe6\xf2\x74\x42\x9b\xc9\x5a\xd1\xa8\x1d\x3c\xb6\x90\xef\x99\xf0\x9f\x21\xa3\xbc\x37\x22\x43\x2e\xbf\x67\x8d\xd2\x35\xc2\xa7\x8b\x55\xff\xb9\xec\x6f\x9d\xda\x1f\xdd\xb1\x23\x32\xa0\xb3\xcb\x55\x76\x37\x53\xbb\xb2\x07\xbb\xc4\x8d\xd9\xc6\xec\x82\x4c\xe5\xce\x5f\x9d\xca\x11\xa3\x7b\xaa\x67\x37\x22\x7b\x33\xd7\xf5\xd2\xe8\xb3\x58\x6d\xd6\xa4\x26\x8f\x7c\xf7\xad\xc6\x0b\xb6\xab\x63\xd5\x31\xae\x35\x6e\x5c\xaa\xbe\xc3\xe7\xe8\xc6\x7a\x5c\x68\x6c\x34\x89\xc6\x09\x72\xa1\x53\x22\x7f\x6b\x7c\x3e\x53\xff\x84\xd8\x60\xaf\x9c\x9b\x63\x37\xa7\x7c\x6a\xe1\x99\xca\xd9\x73\xe4\x27\x6e\xe7\x16\x9f\xb5\x9e\x41\x1c\xe3\xff\x58\xbe\xfb\x4c\x7d\x55\x13\x83\xb9\xea\xdf\xcd\xf4\x3d\x4b\x54\x16\xe8\x90\x21\xc6\xe7\x7c\x2b\x95\x7f\xb0\xbf\xf9\x33\x11\x9a\x5a\xfe\xa6\xb1\xc6\x46\xdd\x29\x3d\xb2\x95\x42\xef\xe5\x3c\x1f\xab\xfd\xb1\x67\xd3\xe8\x1a\x39\x32\x6b\xd5\x27\xe4\x12\xf1\x80\x4c\x9c\x8d\x0d\xab\xc6\xe4\x91\xf5\x2a\xd5\x3c\xc4\x5f\xc8\x0f\x3d\xfc\xb1\x2d\x32\x04\xdb\x77\x9a\x2f\x9d\xd0\x95\x33\xe5\x93\xcd\xd5\x26\xb1\xd9\x0b\x3f\x20\x53\x2e\xdf\xd3\x54\x6d\x87\x5c\xd0\x73\x46\x26\xfc\x92\x5a\xf9\x12\x77\xc4\x2a\x39\x92\x52\x07\x62\xfd\x8e\x1d\xdd\x5c\x73\x0a\xbd\xf3\x46\x73\x07\x9f\x27\x95\xc6\x05\x3e\x2b\xf9\xe6\x54\xdf\x62\xae\xf2\x39\xe2\x51\xd6\xf2\x9d\xef\x67\xca\x8b\x98\x6d\x84\x7f\x5a\xaa\xcd\x89\x4f\x6a\x0f\xf9\xe8\x88\x4b\x6a\x45\xab\xf9\x01\x0d\xb6\xc0\x3f\xc4\x45\xee\x55\x86\xac\xd5\x38\xa7\x46\xa4\xb9\xca\x4b\x5c\x06\xfd\xe7\x7a\x2e\x36\x20\x2e\xc9\x1b\xea\x0d\xf1\x04\x7d\x38\xa7\x50\x9f\x20\x4b\xa8\x83\xb2\xe6\x1b\x8d\x9d\x32\x56\xfe\xd4\x33\x74\x6e\x5b\x95\x89\xdf\xd8\x3c\x2b\xd5\x6e\x9e\x73\x85\x6f\x21\x67\x75\x4e\x6b\x50\x4e\xac\x41\x97\x6a\x8c\xe1\x3b\x7c\x0e\x0f\xd6\x52\xf8\xce\x35\x1f\xa8\x87\xf8\x9b\xbc\xad\xac\x9e\xc2\x1f\x1f\x38\xe8\x0a\xd5\xbb\x6e\xd4\x0e\xd8\x98\x78\xe5\x0c\x7c\x48\x5d\x46\x5f\xe2\xa4\xc3\xbe\x8d\xd6\x49\x6a\x98\x9f\x69\xfc\x97\xd4\xac\x4e\x75\xca\x89\x7f\x7c\x25\xeb\x75\xa5\xfe\xa5\x2e\x84\x5e\x50\x6a\x2d\xaf\x9d\xfa\x9c\xb8\x22\x8e\x76\xbd\x81\xda\xc7\xe3\xbc\xd6\x39\x72\x88\x5a\x4e\x3d\x8a\xf3\x1d\xdd\xf1\x6e\x4a\xfc\xa8\x86\x64\x43\xcd\xbe\x61\x71\x37\xfa\xdc\x19\x36\x65\x4a\xfa\xb8\x3e\x77\x22\x94\xc7\x1f\x7b\xef\x38\x16\xea\xc9\xed\xe8\xf2\x51\xfc\x91\xf8\x6f\x61\xf6\xba\x2b\x71\x18\xbe\x6e\x27\xdc\x4f\xd1\xff\xb1\xc1\xf2\x76\x1e\x0c\x13\x9d\x30\xff\x60\x4c\x78\xcb\x00\x75\x16\x7d\x82\xca\x11\x73\xd3\x59\x94\xcc\xaa\xea\x24\x62\x04\x3a\xbb\x3b\x21\x8d\xb3\x59\x31\x09\xeb\x0c\x36\x67\x3a\xf8\xfc\x6b\xd5\xdf\x8c\x93\x93\x28\x9e\xc8\x04\xeb\x90\xe2\xbb\x60\x82\xb7\x41\xef\xb3\xc8\xd4\x47\xc4\xb3\x28\xfc\x79\x77\xeb\x45\x77\xf2\xd0\xb0\x72\xe7\x92\xf7\xd4\x21\x85\x46\x15\x9a\x43\xae\x8d\x21\x0c\x02\xad\x06\x78\x6a\xcd\x34\x6d\xb4\x40\x42\x03\x3f\x12\x91\x42\x5d\x92\x40\x99\xf2\x25\x21\xe3\x56\x0b\x16\x34\xbc\x97\x99\x36\xe9\xd2\x12\x2f\xab\x8c\xff\x5c\xf9\x73\x4e\x5a\x6b\xf3\x21\xd9\x59\xa3\x79\x52\x58\x48\x74\x8a\x13\x0d\x8a\x06\x5d\xc9\xbe\xd4\x9e\xd0\xb0\xbd\x26\x1a\xc3\x45\x18\x8a\xbc\x36\xb2\xd8\x92\x90\x42\x4c\xc1\xa4\xe9\x30\x8c\x70\x06\x6b\x24\x31\xbc\x29\x60\x99\x35\x7f\x74\xeb\xec\x99\xd9\xbe\xca\x68\x28\xfa\x14\xcd\xbc\xf9\xb3\xb9\x23\x43\x90\x27\xd1\xa4\xde\x9d\x59\x54\x5a\x44\x90\x99\x81\x85\x46\x91\xdb\x10\x46\xf1\x0c\x83\x1b\xf6\x73\x5a\xac\xd1\x8f\x82\x05\x2d\xcd\x9c\x26\x40\x71\xe2\x8c\x38\xbd\x5f\x40\x90\xa9\xb6\xc6\x1b\x0a\xbd\xbf\xe3\xdb\x83\x05\xe4\xfd\x20\xf9\xec\xc2\xf1\x3e\xbb\xfd\x05\xe3\x03\xf0\xe1\xc1\x42\xf1\x3e\xbf\x27\x14\x88\xbd\xfa\x7d\xb1\xc2\x70\x4f\xb5\x5d\x41\x48\x8b\xaf\x5f\x0f\xee\x01\x3a\x7f\x95\xaa\x00\xaf\xd4\x46\x65\xde\x43\xb6\x76\xba\xc6\x35\x25\x35\x1e\xb4\x62\xf6\x87\xbd\x89\xbe\x73\x45\xa0\x85\x73\x5e\x97\xeb\x93\x5b\xc6\x05\x39\xbd\x65\x7a\xae\x99\x97\xd9\xb8\xcb\xd5\x83\x73\xe1\x03\xef\x50\x9d\x9c\x55\x26\x1b\x3f\x53\x1b\x1b\xbc\x5d\x4d\xc8\x74\xf4\x09\x72\xd8\x75\x80\xf1\xb1\x95\x27\x49\x75\x0c\xa2\x02\x90\xf9\xce\x59\xf5\x28\x74\x4c\x67\x6c\x9b\xdb\xf8\x9e\xc4\xf7\xb3\x3b\xb5\xea\xe8\xed\x2a\xc3\xf5\xe3\xf1\xec\xde\xe7\xf2\xcf\xce\xf1\x7d\x4c\xf7\x67\xfa\x5e\x08\xf1\xc1\x7c\xdf\xc7\xfb\x09\x59\xff\x80\xde\x5f\x2c\xf7\x0f\x28\xbb\xab\x00\x49\xf2\xf5\x2b\xc0\x07\x40\xed\x5f\x21\xff\x89\xfb\x5d\x8e\x93\xab\xe1\x2c\xcb\x41\xf2\xf8\x53\x73\x9e\x1c\x6e\x6a\x9b\x28\x6a\xe5\xcd\x39\xc8\x10\xce\x9a\xeb\x15\x81\xdf\xbb\xdc\x0e\xdd\x36\xbb\x9f\x93\x5c\x01\x81\x11\xb8\x2e\x61\x37\xae\x43\x8f\xe7\xe4\x7d\x27\x7c\x76\x46\xde\x67\xb9\x3f\x1f\xf7\x00\xf5\x0f\x66\xe3\x7d\xbe\x4f\xc8\xc5\x83\xfa\x7e\xb1\x4c\xdc\xab\xa6\xe5\x61\x11\x7f\xfd\x34\xdc\xff\xff\x20\x4f\xcd\x46\x2e\xc3\xf3\x58\xa3\x9f\xae\x05\xe8\x71\x0b\x24\x72\x79\xed\x34\x1b\x98\x6f\x01\xff\xc8\x38\xf6\x17\xa9\xd2\xd2\xc5\x98\x93\x99\x4b\x01\x9a\x62\x03\x43\x98\x21\xc3\xdc\x69\x73\x38\x59\x19\x2e\xfb\x06\x70\x39\x03\x1d\x99\x75\x99\x9b\x59\xe3\x72\xcc\xac\xcd\xe5\x9b\x8b\x2c\xc0\x40\x6c\xc0\x1a\xf3\x6f\x90\xc5\xe9\x85\xbf\xab\xf5\x3d\xb5\x4c\x62\x2f\x97\x74\x66\x69\xf6\xd3\x0d\x01\x0b\x00\x31\x00\x52\xb8\xb0\x03\x16\x71\x79\x4e\x0d\x2c\x00\x7c\x09\xdd\x32\xd3\xb9\x3d\x37\x70\x32\x00\x65\x00\x39\x99\x82\x78\x85\x81\x39\xb5\xd9\xc3\x1b\xb0\x0a\xa0\x1a\x1b\x40\x53\x94\xba\x06\x30\x04\xaf\xaa\xb5\x3b\x42\xa3\xa0\x5b\x6e\x15\x00\x70\x00\xc0\x0b\xc0\x04\xb9\x01\x11\xd0\x1d\x20\x36\xd8\xa1\x54\xe0\xb1\xb6\xca\x02\x00\x48\x57\x77\xb5\x76\x7c\x40\x1c\xaa\x27\xa0\x14\xfb\x59\x07\x3c\x05\x64\x00\x2c\x40\xd7\x00\x3e\x65\x0a\x6c\xa1\xf3\xdc\x40\x27\x78\xe3\xc3\xa6\xd2\x29\x82\xc9\xa2\xb0\x89\x03\xdf\x00\x20\xa1\x4b\x00\x53\xb1\x05\x3e\x28\xd5\xd7\xe8\x1d\x6c\x54\x2b\xf8\x1b\x64\x91\xef\x33\x03\xb9\x00\x2e\x00\x4b\x90\x3d\x35\x50\x97\x38\xc2\x56\x00\x63\x54\x5d\x40\x4a\xc0\x53\xe8\x01\xae\x00\x87\x6a\x03\x3b\x91\x8f\x7d\x9c\x99\x9a\x2c\x99\xc5\x67\x00\x5d\x1b\x3d\x97\x29\xae\x33\xe0\x1b\x40\x16\x5a\x26\x1a\xec\x4c\x3c\x31\x49\xd5\x06\x24\xe2\x0f\xc0\x3c\xc0\x16\xe4\x4e\xed\x6e\x83\x5c\x00\x7b\x80\x4b\x8d\xf1\x72\x06\x4c\x05\x70\xac\x52\x10\x89\x18\x63\x1f\x40\x51\x65\x20\x17\xdd\x07\x7d\x00\xba\xd9\x1f\x40\x3c\xa7\xb1\x8a\xaf\xb0\x03\x7b\x2a\xab\xfc\xc4\x58\x00\x8a\x66\x7a\xf7\x44\x26\x57\x19\xf0\xed\x34\x4f\x39\x3b\x31\x79\xb8\x77\x11\x23\xb1\x81\x61\x80\x73\xd8\x26\x80\xec\x06\x1e\x03\x2e\x71\x16\xb2\x38\x03\xf4\x5a\xbb\xeb\x66\x99\xfa\x0e\xbf\x05\x10\xb5\x51\xff\x32\x41\xee\xf4\x09\xf9\xd0\x69\xa7\x0a\x31\xe8\xd4\xee\xe4\x06\x20\x1c\xa0\x16\xf6\x23\xb7\x82\x6d\xbd\xc6\x10\x76\x23\x27\xa0\x05\x44\xed\x0c\x78\xfd\xb0\xb3\x91\xaf\xf8\x3b\xe8\xd9\x6a\xce\x86\x7b\xe7\x83\x9d\xed\x60\x5d\xfb\xec\x06\x77\x90\xf3\xfe\x3e\x77\xf8\x3f\x9a\x1f\x6c\x77\x07\x4f\x79\x42\xd7\x7b\xcc\x16\xf7\x9a\xdf\xff\x02\x00\x00\xff\xff\x3c\x2b\x49\x80\x00\x20\x00\x00")
func dbMigrationsAssetsGoBytes() ([]byte, error) {
return bindataRead(
......
package db
import (
"encoding/base64"
"errors"
"fmt"
"strconv"
......@@ -31,7 +32,7 @@ type refreshTokenRepo struct {
type refreshTokenModel struct {
ID int64 `db:"id"`
PayloadHash string `db:"payload_hash"`
PayloadHash []byte `db:"payload_hash"`
// TODO(yifan): Use some sort of foreign key to manage database level
// data integrity.
UserID string `db:"user_id"`
......@@ -39,25 +40,29 @@ type refreshTokenModel struct {
}
// buildToken combines the token ID and token payload to create a new token.
func buildToken(tokenID int64, tokenPayload string) string {
return fmt.Sprintf("%d%s%s", tokenID, refresh.TokenDelimer, tokenPayload)
func buildToken(tokenID int64, tokenPayload []byte) string {
return fmt.Sprintf("%d%s%s", tokenID, refresh.TokenDelimer, base64.URLEncoding.EncodeToString(tokenPayload))
}
// parseToken parses a token and returns the token ID and token payload.
func parseToken(token string) (int64, string, error) {
func parseToken(token string) (int64, []byte, error) {
parts := strings.SplitN(token, refresh.TokenDelimer, 2)
if len(parts) != 2 {
return -1, "", refresh.ErrorInvalidToken
return -1, nil, refresh.ErrorInvalidToken
}
id, err := strconv.ParseInt(parts[0], 0, 64)
if err != nil {
return -1, "", refresh.ErrorInvalidToken
return -1, nil, refresh.ErrorInvalidToken
}
return id, parts[1], nil
tokenPayload, err := base64.URLEncoding.DecodeString(parts[1])
if err != nil {
return -1, nil, refresh.ErrorInvalidToken
}
return id, tokenPayload, nil
}
func checkTokenPayload(payloadHash, payload string) error {
if err := bcrypt.CompareHashAndPassword([]byte(payloadHash), []byte(payload)); err != nil {
func checkTokenPayload(payloadHash, payload []byte) error {
if err := bcrypt.CompareHashAndPassword(payloadHash, payload); err != nil {
switch err {
case bcrypt.ErrMismatchedHashAndPassword:
return refresh.ErrorInvalidToken
......@@ -89,13 +94,13 @@ func (r *refreshTokenRepo) Create(userID, clientID string) (string, error) {
return "", err
}
payloadHash, err := bcrypt.GenerateFromPassword([]byte(tokenPayload), bcrypt.DefaultCost)
payloadHash, err := bcrypt.GenerateFromPassword(tokenPayload, bcrypt.DefaultCost)
if err != nil {
return "", err
}
record := &refreshTokenModel{
PayloadHash: string(payloadHash),
PayloadHash: payloadHash,
UserID: userID,
ClientID: clientID,
}
......@@ -109,6 +114,7 @@ func (r *refreshTokenRepo) Create(userID, clientID string) (string, error) {
func (r *refreshTokenRepo) Verify(clientID, token string) (string, error) {
tokenID, tokenPayload, err := parseToken(token)
if err != nil {
return "", err
}
......
package functional
import (
"encoding/base64"
"fmt"
"net/url"
"os"
......@@ -342,6 +343,12 @@ func TestDBClientIdentityAll(t *testing.T) {
}
}
// buildRefreshToken combines the token ID and token payload to create a new token.
// used in the tests to created a refresh token.
func buildRefreshToken(tokenID int64, tokenPayload []byte) string {
return fmt.Sprintf("%d%s%s", tokenID, refresh.TokenDelimer, base64.URLEncoding.EncodeToString(tokenPayload))
}
func TestDBRefreshRepoCreate(t *testing.T) {
r := db.NewRefreshTokenRepo(connect(t))
......@@ -383,6 +390,13 @@ func TestDBRefreshRepoVerify(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
badTokenPayload, err := refresh.DefaultRefreshTokenGenerator()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
tokenWithBadID := "404" + token[1:]
tokenWithBadPayload := buildRefreshToken(1, badTokenPayload)
tests := []struct {
token string
creds oidc.ClientCredentials
......@@ -390,7 +404,39 @@ func TestDBRefreshRepoVerify(t *testing.T) {
expected string
}{
{
"invalid-token-foo",
"invalid-token-format",
oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"},
refresh.ErrorInvalidToken,
"",
},
{
"b/invalid-base64-encoded-format",
oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"},
refresh.ErrorInvalidToken,
"",
},
{
"1/invalid-base64-encoded-format",
oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"},
refresh.ErrorInvalidToken,
"",
},
{
token + "corrupted-token-payload",
oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"},
refresh.ErrorInvalidToken,
"",
},
{
// The token's ID content is invalid.
tokenWithBadID,
oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"},
refresh.ErrorInvalidToken,
"",
},
{
// The token's payload content is invalid.
tokenWithBadPayload,
oidc.ClientCredentials{ID: "client-foo", Secret: "secret-foo"},
refresh.ErrorInvalidToken,
"",
......@@ -428,13 +474,42 @@ func TestDBRefreshRepoRevoke(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
badTokenPayload, err := refresh.DefaultRefreshTokenGenerator()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
tokenWithBadID := "404" + token[1:]
tokenWithBadPayload := buildRefreshToken(1, badTokenPayload)
tests := []struct {
token string
userID string
err error
}{
{
"invalid-token-foo",
"invalid-token-format",
"user-foo",
refresh.ErrorInvalidToken,
},
{
"1/invalid-base64-encoded-format",
"user-foo",
refresh.ErrorInvalidToken,
},
{
token + "corrupted-token-payload",
"user-foo",
refresh.ErrorInvalidToken,
},
{
// The token's ID is invalid.
tokenWithBadID,
"user-foo",
refresh.ErrorInvalidToken,
},
{
// The token's payload is invalid.
tokenWithBadPayload,
"user-foo",
refresh.ErrorInvalidToken,
},
......
......@@ -10,9 +10,9 @@ import (
// The tokens are in the form { refresh-1, refresh-2 ... refresh-n}.
func NewTestRefreshTokenRepo() (refresh.RefreshTokenRepo, error) {
var tokenIdx int
tokenGenerator := func() (string, error) {
tokenGenerator := func() ([]byte, error) {
tokenIdx++
return fmt.Sprintf("refresh-%d", tokenIdx), nil
return []byte(fmt.Sprintf("refresh-%d", tokenIdx)), nil
}
return refresh.NewRefreshTokenRepoWithTokenGenerator(tokenGenerator), nil
}
package refresh
import (
"bytes"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"strconv"
......@@ -17,25 +17,26 @@ const (
var (
ErrorInvalidUserID = errors.New("invalid user ID")
ErrorInvalidClientID = errors.New("invalid client ID")
ErrorInvalidToken = errors.New("invalid token")
ErrorInvalidToken = errors.New("invalid token")
)
type RefreshTokenGenerator func() (string, error)
type RefreshTokenGenerator func() ([]byte, error)
func (g RefreshTokenGenerator) Generate() (string, error) {
func (g RefreshTokenGenerator) Generate() ([]byte, error) {
return g()
}
func DefaultRefreshTokenGenerator() (string, error) {
func DefaultRefreshTokenGenerator() ([]byte, error) {
// TODO(yifan) Remove this duplicated token generate function.
b := make([]byte, DefaultRefreshTokenPayloadLength)
n, err := rand.Read(b)
if err != nil {
return "", err
return nil, err
} else if n != DefaultRefreshTokenPayloadLength {
return "", errors.New("unable to read enough random bytes")
return nil, errors.New("unable to read enough random bytes")
}
return base64.URLEncoding.EncodeToString(b), nil
return b, nil
}
type RefreshTokenRepo interface {
......@@ -52,7 +53,7 @@ type RefreshTokenRepo interface {
}
type refreshToken struct {
payload string
payload []byte
userID string
clientID string
}
......@@ -63,21 +64,21 @@ type memRefreshTokenRepo struct {
}
// buildToken combines the token ID and token payload to create a new token.
func buildToken(tokenID int, tokenPayload string) string {
func buildToken(tokenID int, tokenPayload []byte) string {
return fmt.Sprintf("%d%s%s", tokenID, TokenDelimer, tokenPayload)
}
// parseToken parses a token and returns the token ID and token payload.
func parseToken(token string) (int, string, error) {
func parseToken(token string) (int, []byte, error) {
parts := strings.SplitN(token, TokenDelimer, 2)
if len(parts) != 2 {
return -1, "", ErrorInvalidToken
return -1, nil, ErrorInvalidToken
}
id, err := strconv.Atoi(parts[0])
if err != nil {
return -1, "", ErrorInvalidToken
return -1, nil, ErrorInvalidToken
}
return id, parts[1], nil
return id, []byte(parts[1]), nil
}
// NewRefreshTokenRepo returns an in-memory RefreshTokenRepo useful for development.
......@@ -131,7 +132,7 @@ func (r *memRefreshTokenRepo) Verify(clientID, token string) (string, error) {
return "", ErrorInvalidToken
}
if record.payload != tokenPayload {
if !bytes.Equal(record.payload, tokenPayload) {
return "", ErrorInvalidToken
}
......@@ -153,7 +154,7 @@ func (r *memRefreshTokenRepo) Revoke(userID, token string) error {
return ErrorInvalidToken
}
if record.payload != tokenPayload {
if !bytes.Equal(record.payload, tokenPayload) {
return ErrorInvalidToken
}
......
......@@ -397,7 +397,7 @@ func TestServerTokenFail(t *testing.T) {
signer jose.Signer
argCC oidc.ClientCredentials
argKey string
err string
err error
scope []string
refreshToken string
}{
......@@ -423,7 +423,7 @@ func TestServerTokenFail(t *testing.T) {
signer: signerFixture,
argCC: ccFixture,
argKey: "foo",
err: oauth2.ErrorInvalidGrant,
err: oauth2.NewError(oauth2.ErrorInvalidGrant),
scope: []string{"openid", "offline_access"},
},
......@@ -432,7 +432,7 @@ func TestServerTokenFail(t *testing.T) {
signer: signerFixture,
argCC: oidc.ClientCredentials{ID: "YYY"},
argKey: keyFixture,
err: oauth2.ErrorInvalidClient,
err: oauth2.NewError(oauth2.ErrorInvalidClient),
scope: []string{"openid", "offline_access"},
},
......@@ -441,7 +441,7 @@ func TestServerTokenFail(t *testing.T) {
signer: &StaticSigner{sig: nil, err: errors.New("fail")},
argCC: ccFixture,
argKey: keyFixture,
err: oauth2.ErrorServerError,
err: oauth2.NewError(oauth2.ErrorServerError),
scope: []string{"openid", "offline_access"},
},
}
......@@ -502,18 +502,14 @@ func TestServerTokenFail(t *testing.T) {
t.Fatalf("case %d: expect refresh token %q, got %q", i, tt.refreshToken, token)
panic("")
}
if tt.err == "" {
if err != nil {
t.Errorf("case %d: got non-nil error: %v", i, err)
} else if jwt == nil {
t.Errorf("case %d: got nil JWT", i)
}
} else {
if err.Error() != tt.err {
t.Errorf("case %d: want err %q, got %q", i, tt.err, err.Error())
} else if jwt != nil {
t.Errorf("case %d: got non-nil JWT", i)
}
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("case %d: expect %v, got %v", i, tt.err, err)
}
if err == nil && jwt == nil {
t.Errorf("case %d: got nil JWT", i)
}
if err != nil && jwt != nil {
t.Errorf("case %d: got non-nil JWT %v", i, jwt)
}
}
}
......@@ -537,7 +533,7 @@ func TestServerRefreshToken(t *testing.T) {
clientID string // The client that associates with the token.
creds oidc.ClientCredentials
signer jose.Signer
err string
err error
}{
// Everything is good.
{
......@@ -545,7 +541,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
credXXX,
signerFixture,
"",
nil,
},
// Invalid refresh token(malformatted).
{
......@@ -553,15 +549,23 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
credXXX,
signerFixture,
oauth2.ErrorInvalidRequest,
oauth2.NewError(oauth2.ErrorInvalidRequest),
},
// Invalid refresh token.
// Invalid refresh token(invalid payload content).
{
"0/refresh-1",
"0/refresh-2",
"XXX",
credXXX,
signerFixture,
oauth2.ErrorInvalidRequest,
oauth2.NewError(oauth2.ErrorInvalidRequest),
},
// Invalid refresh token(invalid ID content).
{
"1/refresh-2",
"XXX",
credXXX,
signerFixture,
oauth2.NewError(oauth2.ErrorInvalidRequest),
},
// Invalid client(client is not associated with the token).
{
......@@ -569,7 +573,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
credYYY,
signerFixture,
oauth2.ErrorInvalidClient,
oauth2.NewError(oauth2.ErrorInvalidClient),
},
// Invalid client(no client ID).
{
......@@ -577,7 +581,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
oidc.ClientCredentials{ID: "", Secret: "aaa"},
signerFixture,
oauth2.ErrorInvalidClient,
oauth2.NewError(oauth2.ErrorInvalidClient),
},
// Invalid client(no such client).
{
......@@ -585,7 +589,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
oidc.ClientCredentials{ID: "AAA", Secret: "aaa"},
signerFixture,
oauth2.ErrorInvalidClient,
oauth2.NewError(oauth2.ErrorInvalidClient),
},
// Invalid client(no secrets).
{
......@@ -593,7 +597,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
oidc.ClientCredentials{ID: "XXX"},
signerFixture,
oauth2.ErrorInvalidClient,
oauth2.NewError(oauth2.ErrorInvalidClient),
},
// Invalid client(invalid secret).
{
......@@ -601,7 +605,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
oidc.ClientCredentials{ID: "XXX", Secret: "bad-secret"},
signerFixture,
oauth2.ErrorInvalidClient,
oauth2.NewError(oauth2.ErrorInvalidClient),
},
// Signing operation fails.
{
......@@ -609,7 +613,7 @@ func TestServerRefreshToken(t *testing.T) {
"XXX",
credXXX,
&StaticSigner{sig: nil, err: errors.New("fail")},
oauth2.ErrorServerError,
oauth2.NewError(oauth2.ErrorServerError),
},
}
......@@ -646,10 +650,8 @@ func TestServerRefreshToken(t *testing.T) {
}
jwt, err := srv.RefreshToken(tt.creds, tt.token)
if err != nil {
if err.Error() != tt.err {
t.Errorf("Case %d: expect: %v, got: %v", i, tt.err, err)
}
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("Case %d: expect: %v, got: %v", i, tt.err, err)
}
if jwt != nil {
......@@ -715,7 +717,7 @@ func TestServerRefreshToken(t *testing.T) {
srv.UserRepo = userRepo
_, err = srv.RefreshToken(credXXX, "0/refresh-1")
if err == nil || err.Error() != oauth2.ErrorServerError {
t.Errorf("Expect: %v, got: %v", oauth2.ErrorServerError, err)
if !reflect.DeepEqual(err, oauth2.NewError(oauth2.ErrorServerError)) {
t.Errorf("Expect: %v, got: %v", oauth2.NewError(oauth2.ErrorServerError), err)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment