对于我们的下一个初学者项目,我们将构建一个密码生成器,它不仅可以生成密码,还可以加密并保存密码 - 以便它真正发挥作用。
我们将把代码分成不同的文件,这样我们就不会得到一个大的“main.go”文件。
首先,我们初始化一个 go 项目并创建一个“profile.go”文件,其中包含加密和解密密码的逻辑。
package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "errors" "io" ) // must be 32 characters var key = "askdjasjdbreonfsdfibsdhfgsdfhboo" var ErrMalformedEncryption = errors.New("malformed encryption") // password in small letters so it is not stored type profile struct { Enc, Platform, password string } func (p *profile) encrypt() error { block, err := aes.NewCipher([]byte(key)) if err != nil { return err } gcm, err := cipher.NewGCM(block) if err != nil { return err } nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return err } enc := gcm.Seal(nonce, nonce, []byte(p.password), nil) p.Enc = hex.EncodeToString(enc) return nil } func (p *profile) decrypt() error { block, err := aes.NewCipher([]byte(key)) if err != nil { return err } gcm, err := cipher.NewGCM(block) if err != nil { return err } nsize := gcm.NonceSize() if len(p.Enc) <p>这里我们创建一个包含 3 个字段的配置文件结构 - Enc、平台和密码。 Enc 将保存加密的密码,我们为其生成密码的服务将存储在平台中,而密码将保存实际生成的密码。配置文件结构有两种方法“加密”和“解密”。我们使用 AES - 一种对称密钥加密算法来加密和解密我们的密码。 </p> <p>接下来我们创建一个“store.go”文件,其中包含存储和检索密码的逻辑。<br> </p> <pre class="brush:php;toolbar:false">package main import ( "encoding/gob" "errors" "os" "sync" ) const filename = "profile.bin" var ( ErrInvalidArgs = errors.New("invalid args") ErrNotFound = errors.New("not found") ) type store struct { sync.RWMutex data map[string]*profile } func newStore() (*store, error) { s := &store{ data: make(map[string]*profile), } if err := s.load(); err != nil { return nil, err } return s, nil } func (s *store) load() error { flags := os.O_CREATE | os.O_RDONLY f, err := os.OpenFile(filename, flags, 0644) if err != nil { return err } defer f.Close() info, err := f.Stat() if err != nil { return err } if info.Size() == 0 { return nil } return gob.NewDecoder(f).Decode(&s.data) } func (s *store) save() error { f, err := os.OpenFile(filename, os.O_WRONLY, 0644) if err != nil { return err } defer f.Close() return gob.NewEncoder(f).Encode(s.data) } func (s *store) find(platform string) (string, error) { s.RLock() defer s.RUnlock() p, ok := s.data[platform] if !ok { return "", ErrNotFound } if err := p.decrypt(); err != nil { return "", err } return p.password, nil } func (s *store) add(platform, password string) error { if platform == "" { return ErrInvalidArgs } p := &profile{ Platform: platform, password: password, } if err := p.encrypt(); err != nil { return err } s.Lock() defer s.Unlock() s.data[platform] = p return s.save() }
我们选择 gob 文件进行存储,因为它们不完全是人类可读的。如果文件被泄露,您的密码是安全的,因为它们将被加密并且很难读取。 store 结构包含加载、查找和保存到 gob 文件的方法。我们将密码保存在字典中。我们还使用互斥体来确保字典并发安全。需要注意的重要一点是,我们不会存储纯生成的密码 - 我们将存储其加密值。
现在让我们编写几个实际生成密码的函数。创建一个“password.go”文件并输入以下内容
package main import ( "math" "math/rand" "slices" "strings" ) const ( half = .5 onethird = .3 onefourth = .25 ) var ( randlowers = randFromSeed(lowers()) randuppers = randFromSeed(uppers()) randdigits = randFromSeed(digits()) randsymbols = randFromSeed(symbols()) ) var basicPassword = randlowers func mediumPassword(n int) string { frac := math.Round(float64(n) * half) pwd := basicPassword(n) return pwd[:n-int(frac)] + randuppers(int(frac)) } func hardPassword(n int) string { pwd := mediumPassword(n) frac := math.Round(float64(n) * onethird) return pwd[:n-int(frac)] + randdigits(int(frac)) } func xhardPassword(n int) string { pwd := hardPassword(n) frac := math.Round(float64(n) * onefourth) return pwd[:n-int(frac)] + randsymbols(int(frac)) } func randFromSeed(seed string) func(int) string { return func(n int) string { var b strings.Builder for range n { b.WriteByte(seed[rand.Intn(len(seed))]) } return b.String() } } func lowers() string { var b strings.Builder for i := 'a'; i <p>在这里,我们编写了生成不同难度级别密码的函数。 basicPassword 函数生成随机小字母字符串。 mediumPassword 函数从 basicPassword 函数中获取一小部分字符,并向其中添加随机大写字母。 HardPassword 函数对mediumPassword 执行相同的操作,但添加了数字。 xhardPassword 执行相同操作并添加符号。 shuffle 函数完全符合您对切片的期望,而 shuffleStr 则对字符串进行洗牌。</p> <p>现在让我们把所有东西放在一起。创建一个“main.go”文件并输入以下内容<br> </p> <pre class="brush:php;toolbar:false">package main import ( "errors" "flag" "fmt" "log" "regexp" "strconv" "strings" ) var usage = ` Usage ----- --get platform=[string] - Gets saved password for a platform --set platform=[string] len=[int] level=(basic|medium|hard|xhard) - Creates and saves a password ` var ErrUsage = errors.New(usage) var pattern = regexp.MustCompile(`\S+=\S+`) type level int const ( _ level = iota level_basic level_medium level_hard level_xhard ) var level_key = map[string]level{ "basic": level_basic, "medium": level_medium, "hard": level_hard, "xhard": level_xhard, } type commands struct { get, set bool } func createCommands() (c commands) { flag.BoolVar(&c.get, "get", false, "get password for platform") flag.BoolVar(&c.set, "set", false, "set password for platform") flag.Parse() return } func (c commands) exec(store *store) (string, error) { switch { case c.get: return c.getPassword(store) case c.set: return c.setPassword(store) default: return "", ErrUsage } } func (c commands) getPassword(store *store) (string, error) { params, err := c.parse() if err != nil { return "", err } return store.find(params["platform"]) } func (c commands) setPassword(store *store) (string, error) { params, err := c.parse() if err != nil { return "", err } var password string n, err := strconv.Atoi(params["len"]) if err != nil { return "", err } if n <p>我们使用标志来指定我们期望应用程序的行为方式。 “--get”获取密码,“--set”生成并保存密码。要设置密码,用户提供带有标志的参数,以指示应用程序生成和保存的密码类型。要获取密码,用户还提供参数来指定要检索的密码。</p> <p>您现在可以运行“go build”来构建二进制文件并测试应用程序。</p> <p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173158638678335.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="Let"></p>
以上是让我们构建一个我们可以实际使用的密码生成器的详细内容。更多信息请关注PHP中文网其他相关文章!

本文演示了创建模拟和存根进行单元测试。 它强调使用接口,提供模拟实现的示例,并讨论最佳实践,例如保持模拟集中并使用断言库。 文章

本文探讨了GO的仿制药自定义类型约束。 它详细介绍了界面如何定义通用功能的最低类型要求,从而改善了类型的安全性和代码可重复使用性。 本文还讨论了局限性和最佳实践

本文使用跟踪工具探讨了GO应用程序执行流。 它讨论了手册和自动仪器技术,比较诸如Jaeger,Zipkin和Opentelemetry之类的工具,并突出显示有效的数据可视化

本文讨论了GO的反思软件包,用于运行时操作代码,对序列化,通用编程等有益。它警告性能成本,例如较慢的执行和更高的内存使用,建议明智的使用和最佳

本文讨论了通过go.mod,涵盖规范,更新和冲突解决方案管理GO模块依赖关系。它强调了最佳实践,例如语义版本控制和定期更新。

本文讨论了GO中使用表驱动的测试,该方法使用测试用例表来测试具有多个输入和结果的功能。它突出了诸如提高的可读性,降低重复,可伸缩性,一致性和A


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 英文版
推荐:为Win版本,支持代码提示!