-
Notifications
You must be signed in to change notification settings - Fork 114
/
resource_password.go
134 lines (111 loc) · 4.28 KB
/
resource_password.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
package provider
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"golang.org/x/crypto/bcrypt"
)
// resourcePassword and resourceString both use the same set of CustomizeDiffFunc(s) in order to handle the deprecation
// of the `number` attribute and the simultaneous addition of the `numeric` attribute. planDefaultIfAllNull handles
// ensuring that both `number` and `numeric` default to `true` when they are both absent from config.
// planSyncIfChange handles keeping number and numeric in-sync when either one has been changed.
func resourcePassword() *schema.Resource {
customizeDiffFuncs := planDefaultIfAllNull(true, "number", "numeric")
customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("number", "numeric"))
customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("numeric", "number"))
return &schema.Resource{
Description: "Identical to [random_string](string.html) with the exception that the result is " +
"treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive " +
"data handling in the [Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).\n" +
"\n" +
"This resource *does* use a cryptographic random number generator.",
CreateContext: createPassword,
ReadContext: readNil,
DeleteContext: RemoveResourceFromState,
Schema: passwordSchemaV2(),
Importer: &schema.ResourceImporter{
StateContext: importPasswordFunc,
},
SchemaVersion: 2,
StateUpgraders: []schema.StateUpgrader{
{
Version: 0,
Type: resourcePasswordV0().CoreConfigSchema().ImpliedType(),
Upgrade: resourcePasswordStateUpgradeV0,
},
{
Version: 1,
Type: resourcePasswordV1().CoreConfigSchema().ImpliedType(),
Upgrade: resourcePasswordStateUpgradeV1,
},
},
CustomizeDiff: customdiff.All(
customizeDiffFuncs...,
),
}
}
func createPassword(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
diags := createStringFunc(true)(ctx, d, meta)
if diags.HasError() {
return diags
}
hash, err := generateHash(d.Get("result").(string))
if err != nil {
diags = append(diags, diag.Errorf("err: %s", err)...)
return diags
}
if err := d.Set("bcrypt_hash", hash); err != nil {
diags = append(diags, diag.Errorf("err: %s", err)...)
return diags
}
return nil
}
func importPasswordFunc(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
val := d.Id()
d.SetId("none")
if err := d.Set("result", val); err != nil {
return nil, fmt.Errorf("resource password import failed, error setting result: %w", err)
}
hash, err := generateHash(val)
if err != nil {
return nil, fmt.Errorf("resource password import failed, generate hash error: %w", err)
}
if err := d.Set("bcrypt_hash", hash); err != nil {
return nil, fmt.Errorf("resource password import failed, error setting bcrypt_hash: %w", err)
}
return []*schema.ResourceData{d}, nil
}
func resourcePasswordV1() *schema.Resource {
return &schema.Resource{
Schema: passwordSchemaV1(),
}
}
func resourcePasswordStateUpgradeV1(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
return resourceStateUpgradeAddNumeric("password")(ctx, rawState, meta)
}
func resourcePasswordV0() *schema.Resource {
return &schema.Resource{
Schema: passwordSchemaV0(),
}
}
func resourcePasswordStateUpgradeV0(_ context.Context, rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
if rawState == nil {
return nil, fmt.Errorf("resource password state upgrade failed, state is nil")
}
result, ok := rawState["result"].(string)
if !ok {
return nil, fmt.Errorf("resource password state upgrade failed, result is not a string: %T", rawState["result"])
}
hash, err := generateHash(result)
if err != nil {
return nil, fmt.Errorf("resource password state upgrade failed, generate hash error: %w", err)
}
rawState["bcrypt_hash"] = hash
return rawState, nil
}
func generateHash(toHash string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(toHash), bcrypt.DefaultCost)
return string(hash), err
}