/
schemaStore.go
153 lines (136 loc) · 4.84 KB
/
schemaStore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Copyright 2020, Cossack Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package config
import (
"gopkg.in/yaml.v2"
)
// UseMySQL represent constant for switching mode of encryptor config
const (
UseMySQL = true
UsePostgreSQL = false
)
// TableSchemaStore fetches schema for encryptable tables in the database.
type TableSchemaStore interface {
GetDatabaseSettings() DatabaseSettings
// GetTableSchema returns schema for given table if configured, or nil otherwise.
GetTableSchema(tableName string) TableSchema
GetGlobalSettingsMask() SettingMask
}
// defaultValues store default values for config
type defaultValues struct {
CryptoEnvelope *CryptoEnvelopeType `yaml:"crypto_envelope"`
ReEncryptToAcraBlock *bool `yaml:"reencrypting_to_acrablocks"`
ConsistentTokenization *bool `yaml:"consistent_tokenization"`
}
// GetCryptoEnvelope returns type of crypto envelope
func (d defaultValues) GetCryptoEnvelope() CryptoEnvelopeType {
if d.CryptoEnvelope == nil {
return CryptoEnvelopeTypeAcraBlock
}
return *d.CryptoEnvelope
}
// GetConsistentTokenization returns if consistent tokenization by default
func (d defaultValues) GetConsistentTokenization() bool {
if d.ConsistentTokenization == nil {
return false
}
return *d.ConsistentTokenization
}
// ShouldReEncryptAcraStructToAcraBlock return true if should re-encrypt data with AcraBlock
func (d defaultValues) ShouldReEncryptAcraStructToAcraBlock() bool {
if d.ReEncryptToAcraBlock == nil {
return true
}
return *d.ReEncryptToAcraBlock
}
type storeConfig struct {
DatabaseSettings *databaseSettings `yaml:"database_settings"`
Defaults *defaultValues
Schemas []*tableSchema
}
// MapTableSchemaStore store schemas per table name
type MapTableSchemaStore struct {
databaseSettings *databaseSettings
schemas map[string]*tableSchema
globalMask SettingMask
}
// NewMapTableSchemaStore return new MapTableSchemaStore
func NewMapTableSchemaStore() (*MapTableSchemaStore, error) {
return &MapTableSchemaStore{schemas: make(map[string]*tableSchema)}, nil
}
// MapTableSchemaStoreFromConfig parse config and return MapTableSchemaStore with data from config
func MapTableSchemaStoreFromConfig(config []byte, useMySQL bool) (*MapTableSchemaStore, error) {
storeConfig := &storeConfig{}
if err := yaml.Unmarshal(config, &storeConfig); err != nil {
return nil, err
}
if storeConfig.Defaults == nil {
storeConfig.Defaults = &defaultValues{}
}
if storeConfig.Defaults != nil && storeConfig.Defaults.CryptoEnvelope != nil {
if err := ValidateCryptoEnvelopeType(*storeConfig.Defaults.CryptoEnvelope); err != nil {
return nil, err
}
}
var mask SettingMask
mapSchemas := make(map[string]*tableSchema, len(storeConfig.Schemas))
for _, schema := range storeConfig.Schemas {
for _, setting := range schema.EncryptionColumnSettings {
setting.applyDefaults(*storeConfig.Defaults)
if err := setting.Init(useMySQL); err != nil {
return nil, err
}
mask |= setting.settingMask
}
mapSchemas[schema.TableName] = schema
}
return &MapTableSchemaStore{
databaseSettings: storeConfig.DatabaseSettings,
schemas: mapSchemas,
globalMask: mask,
}, nil
}
// GetDatabaseSettings return struct with database-specific configuration
func (store *MapTableSchemaStore) GetDatabaseSettings() DatabaseSettings {
// Create default set of values so GetDatabaseSettings() won't fail
// if this section is missing in the config file or if the config
// file was not specified at all and MapTableSchemaStoreFromConfig()
// never executed
if store.databaseSettings == nil {
defaultMySQLCaseSensitiveTableID := false
return &databaseSettings{
MysqlSetting: mysqlSetting{
CaseSensitiveTableIdentifiers: &defaultMySQLCaseSensitiveTableID,
},
PostgresqlSetting: postgresqlSetting{},
}
}
return store.databaseSettings
}
// GetGlobalSettingsMask return OR of all masks of column settings
func (store *MapTableSchemaStore) GetGlobalSettingsMask() SettingMask {
return store.globalMask
}
// GetTableSchema return table schema if exists otherwise nil
func (store *MapTableSchemaStore) GetTableSchema(tableName string) TableSchema {
// Explicitly check for presence and return explicit "nil" value
// so that returned interface is "== nil".
schema, ok := store.schemas[tableName]
if ok {
return schema
}
return nil
}