【js学习笔记】“花密”算法本地化

需求

花密(https://flowerpassword.com)是一种轻量级的密码管理工具,通过仅记忆一个私人密码,利用不同关键字实时生成相应的密码,来避免不同网站使用同样的密码,以及避免记忆多个网站的多个密码。

花密目前仅提供网页页面,每次需要密码的时候,还要联网打开页面,有时也不太方便。因此希望将花密迁移到本地使用,比如直接在命令行里面输入 password ss 就可以获得最终密码。用 flower password 做关键字在 github 上搜索发现,有人发布了疑似花密的算法(github.com/xlsdg/flowerpassword.js),经验证发现算法正确。也有人已经发布了疑似花密算法的命令行工具 (github.com/xlsdg/flower-password-cli),不过代码略复杂,一时没怎么看懂,因此决定选择前者。

测试代码

新建一个目录 flowerpassword,进入其中后运行 npm install --save flowerpassword.js,即将所需模块下载到本地。然后新建测试代码 test.js 如下:

import fpCode from 'flowerpassword.js';
console.log(fpCode('mypassword', 'key', 16));

虽然就两句话,但是用 node test.js 本地运行依旧出错,提示 Cannot use import statement outside a module。查询一番后才得知,nodejs 默认使用 CommonJS 语法,而 import 属于 ES6 语法,最简单的解决办法就是将文件名后缀改为 .mjs,然后成功运行。

加入互动

通过 nodejs 的 readline 函数,可以获取用户输入。因此,代码修改如下:

import password from 'flowerpassword.js';
import readline from 'readline';

const r = readline.createInterface({
    input: process.stdin,
    output:process.stdout
})

r.question('?', user_input => {
    console.log(password('mypassword', user_input, 16));
    r.close();
})

这里有个小细节,flowerpassword.js 源代码中使用 export default function fpCode(...){...} 这样的语句,因此我们使用的时候,可以任意命名咱 import 进来的变量(示例代码导入 fpcode,俺们自己的代码使用 password)。如果对方使用 export 而不带 default 的话,就只能用 import { fpCode as password } from ... 这样的语法了。

加密明文

考虑到私人密码(就是前面那个 mypassword)不宜使用明文,为避免视觉泄露,建议将明文加密。最简单的加密就是使用各种编码样式给编码一次即可,比如 base64 编码。我们首先使用 Buffer.from('mypassword').toString('base64') 获得私人密码编码后的字符串(即'bXlwYXNzd29yZA=='),然后在代码中直接使用 Buffer.from('xxx', 'base64').toString() 语句来解密之即可。于是最终代码如下:

import password from 'flowerpassword.js';
import readline from 'readline';

const common = 'bXlwYXNzd29yZA==';

const r = readline.createInterface({
    input: process.stdin,
    output:process.stdout
})

r.question('?', user_input => {
    console.log(password(
        Buffer.from(common, 'base64').toString(), 
        user_input, 
        16
    ));
    r.close();
})

复制到系统剪切板(clipboard)

既然密码出来了,还要用鼠标选中、复制,然后找到合适的地方粘贴,感觉还可以偷懒一点,信息化的指导思想之一就是让代码多跑路,让用户少操作嘛。因此想再次修改代码,让最终的密码直接到系统 clipboard 上,用户只需找地方Ctrl-V 即可。

经查询,nodejs 里面的 child_process 模块里的 exec 函数可以干这个事情。这是个通用函数,用于调用系统功能,实现一些系统级的能力。代码的最后一个语句改为如下:

r.question('?', user_input => {
    const new_password = password(
        Buffer.from(common, 'base64').toString(),
        user_input,
        16
    );
    console.log(new_password);
    exec('clip').stdin.end(new_password)
    r.close();
})

深入 nodejs 之 buffer

这里需要吐槽一下,中文互联网的内容比较差,比如我刚开始搜索 js 加密 的时候,大部分给的答案都是 btoa()atob() 两个函数,但后来认真查看了 nodejs 的官方文档后才知道,这两个函数早就被 nodejs 建议不再使用了。通过阅读 nodejs 的源代码及官方文档,可以得知当前(nodejs v20)官方实现的 encode 总共是以下几种

  • utf8:这个是默认编码,别名 utf-8
  • latin1:别名binary
  • utf16le:别名 usc2ucs-2utf-16le
  • ascii:向下兼容用
  • base64:转码规范见 rfc4648
  • base64url:转码规范见 rfc4648(其实与前者几乎一样,除了没有 = 补齐、将 +/-_ 代替之外)
  • hex

小结

本轮学习 javascript,通过将“花密”算法本地化过程,学习了如下知识点:

  • nodejs 默认支持的 CommonJS 语法与 ES6 语法大略不同及解决办法(改后缀)
  • nodejs 的 readline 函数的基础使用
  • nodejs 的 Buffer 编解码的基础使用与常见编码类型
  • nodejs 的 child_process.exec() 如何实现对系统 clipboard 的访问
  • base64 编码与 base64url 编码的大致规范与区别
  • js 中 export default 与 export 的区别

参考文献

  • 花密原始站点
  • 花密算法发布页
  • nodejs 官方文档之 buffer
  • nodejs 源代码之 buffer
  • rfc4648 之 base64
  • nodejs 之复制到 clipboard

你可能感兴趣的:(javascript,javascript,学习,笔记)