github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/secrets/mysqlmylogin/mysqlmylogin.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package mysqlmylogin provides an extractor for identifying secrets in .mylogin.cnf files. 16 package mysqlmylogin 17 18 import ( 19 "context" 20 "fmt" 21 "path/filepath" 22 23 "github.com/google/osv-scalibr/extractor/filesystem" 24 "github.com/google/osv-scalibr/inventory" 25 "github.com/google/osv-scalibr/plugin" 26 27 "gopkg.in/ini.v1" 28 ) 29 30 // Section is a Veles Secret that holds relevant information for a [Mysql MyLogin](https://dev.mysql.com/doc/refman/8.4/en/option-files.html). 31 type Section struct { 32 SectionName string 33 User string 34 Password string 35 Host string 36 Port string 37 Socket string 38 } 39 40 const ( 41 // Name is the unique name of this extractor. 42 Name = "secrets/mysqlmylogin" 43 ) 44 45 // Extractor extracts mysql credentials from .mylogin.cnf files. 46 type Extractor struct{} 47 48 // New returns a .mylogin.cnf extractor. 49 func New() filesystem.Extractor { return &Extractor{} } 50 51 // Name of the extractor. 52 func (e Extractor) Name() string { return Name } 53 54 // Version of the extractor. 55 func (e Extractor) Version() int { return 0 } 56 57 // Requirements of the extractor. 58 func (e Extractor) Requirements() *plugin.Capabilities { 59 return &plugin.Capabilities{} 60 } 61 62 // FileRequired returns true if the specified file is a .mylogin.cnf file. 63 func (e Extractor) FileRequired(api filesystem.FileAPI) bool { 64 return filepath.Base(api.Path()) == ".mylogin.cnf" 65 } 66 67 // Extract extracts Mysql credentials from .mylogin.cnf file. 68 func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) (inventory.Inventory, error) { 69 var secrets []*inventory.Secret 70 71 plaintext, err := decryptMyLoginCNF(input.Reader) 72 if err != nil { 73 return inventory.Inventory{}, fmt.Errorf("error decrypting file %w", err) 74 } 75 76 cfg, err := ini.Load(plaintext) 77 if err != nil { 78 return inventory.Inventory{}, fmt.Errorf("unable to Load ini structure from %s", input.Path) 79 } 80 81 // Get all sections in the mylogin file 82 sections := cfg.Sections() 83 for _, section := range sections { 84 // The ini library uses a "DEFAULT" section which is always empty 85 // skipping it 86 if section.Name() == ini.DefaultSection { 87 continue 88 } 89 90 // Get all key-value pairs 91 keysMap := section.KeysHash() 92 // Populate struct (keys that don't exist will just be "") 93 s := Section{ 94 SectionName: section.Name(), 95 Host: keysMap["host"], 96 User: keysMap["user"], 97 Password: keysMap["password"], 98 Port: keysMap["port"], 99 Socket: keysMap["socket"], 100 } 101 102 secrets = append(secrets, &inventory.Secret{ 103 Secret: s, 104 Location: input.Path, 105 }) 106 } 107 return inventory.Inventory{Secrets: secrets}, nil 108 }