分类 技术 下的文章

用 GPG 和 Python 的 getpass 模块给你的密码多一层安全保障。

 title=

密码对程序员来说尤其重要。你不应该在不加密的情况下存储它们,而且你也不应该在用户输入密码的时候显示出输入的内容。当我决定要提高我的笔记本电脑的安全性时,这对我来说变得特别重要。我对我的家目录进行了加密,但当我登录后,任何以纯文本形式存储在配置文件中的密码都有可能暴露在偷窥者面前。

具体来说,我使用一个名为 Mutt 的应用作为我的电子邮件客户端。它可以让我在我的 Linux 终端中阅读和撰写电子邮件,但通常它希望在其配置文件中有一个密码。我限制了我的 Mutt 配置文件的权限,以便只有我可以看到它,我是我的笔记本电脑的唯一用户,所以我并不真的担心经过认证的用户会无意中看到我的配置文件。相反,我想保护自己,无论是为了吹嘘还是为了版本控制,不至于心不在焉地把我的配置发布到网上,把我的密码暴露了。此外,虽然我不希望我的系统上有不受欢迎的客人,但我确实想确保入侵者不能通过对我的配置上运行 cat 就获得我的密码。

Python GnuPG

Python 模块 python-gnupggpg 应用的一个 Python 封装。该模块的名字是 python-gnupg,你不要把它和一个叫做 gnupg 的模块混淆。

GnuPG(GPG) 是 Linux 的默认加密系统,我从 2009 年左右开始使用它。我对它很熟悉,对它的安全性有很高的信任。

我决定将我的密码输入 Mutt 的最好方法是将我的密码存储在一个加密的 GPG 文件中,创建一个提示我的 GPG 密码来解锁这个加密文件,然后将密码交给 Mutt(实际上是交给 offlineimap 命令,我用它来同步我的笔记本和电子邮件服务器)。

用 Python 获取用户输入 是非常容易的。对 input 进行调用,无论用户输入什么,都会被存储为一个变量:

print("Enter password: ")
myinput = input()

print("You entered: ", myinput)

我的问题是,当我根据密码提示在终端上输入密码时,我所输入的所有内容对任何从我肩膀上看过去或滚动我的终端历史的人来说都是可见的:

$ ./test.py
Enter password: my-Complex-Passphrase

用 getpass 输入不可见密码

正如通常的情况一样,有一个 Python 模块已经解决了我的问题。这个模块是 getpass4,从用户的角度来看,它的行为和 input 完全一样,只是不显示用户输入的内容。

你可以用 pip 安装这两个模块:

$ python -m pip install --user python-gnupg getpass4

下面是我的 Python 脚本,用于创建密码提示:

#!/usr/bin/env python
# by Seth Kenlon
# GPLv3

# install deps:
# python3 -m pip install --user python-gnupg getpass4

import gnupg
import getpass
from pathlib import Path

def get_api_pass():
  homedir = str(Path.home())
  gpg = gnupg.GPG(gnupghome=os.path.join(homedir,".gnupg"), use_agent=True)
  passwd = getpass.getpass(prompt="Enter your GnuPG password: ", stream=None)

  with open(os.path.join(homedir,'.mutt','pass.gpg'), 'rb') as f:
    apipass = (gpg.decrypt_file(f, passphrase=passwd))

  f.close()

  return str(apipass)
 
if __name__ == "__main__":
  apipass = get_api_pass()
  print(apipass)

如果你想试试,把文件保存为 password_prompt.py。如果你使用 offlineimap 并想在你自己的密码输入中使用这个方案,那么把它保存到某个你可以在 .offlineimaprc 文件中指向 offlineimap 的位置(我使用 ~/.mutt/password_prompt.py)。

测试密码提示

要查看脚本的运行情况,你首先必须创建一个加密文件(我假设你已经设置了 GPG):

$ echo "hello world" > pass
$ gpg --encrypt pass
$ mv pass.gpg ~/.mutt/pass.gpg
$ rm pass

现在运行 Python 脚本:

$ python ~/.mutt/password_prompt.py
Enter your GPG password:
hello world

当你输入时没有任何显示,但只要你正确输入 GPG 口令,你就会看到该测试信息。

将密码提示符与 offlineimap 整合起来

我需要将我的新提示与 offlineimap 命令结合起来。我为这个脚本选择了 Python,因为我知道 offlineimap 可以对 Python 程序进行调用。如果你是一个 offlineimap 用户,你会明白唯一需要的“整合”是在你的 .offlineimaprc 文件中改变两行。

首先,添加一行引用 Python 文件的内容:

pythonfile = ~/.mutt/password_prompt.py

然后将 .offlineimaprc中的 remotepasseval 行改为调用 password_prompt.py中的 get_api_pass() 函数:

remotepasseval = get_api_pass()

配置文件中不再有密码!

安全问题

在你的个人电脑上考虑安全问题有时会让人觉得很偏执。你的 SSH 配置是否真的需要限制为 600?隐藏在名为 .mutt 的无关紧要的电子邮件密码真的重要吗?也许不重要。

然而,知道我没有把敏感数据悄悄地藏在我的配置文件里,使我更容易把文件提交到公共 Git 仓库,把片段复制和粘贴到支持论坛,并以真实好用的配置文件的形式分享我的知识。仅就这一点而言,安全性的提高使我的生活更加轻松。而且有这么多好的 Python 模块可以提供帮助,这很容易实现。


via: https://opensource.com/article/21/7/invisible-passwords-python

作者:Seth Kenlon 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

使用数据库查询操作轻松获取系统信息。

 title=

Linux 提供了很多帮助用户收集主机操作系统信息的命令:列出文件或者目录的属性信息;查询安装的软件包、正在执行的命令、开机时启动的服务;或者了解系统的硬件。

每个命令使用自己的输出格式列出系统的信息。你需要使用 grepsedawk 这样的工具过滤命令输出的结果,以便找到特定的信息。此外,很多这样的信息会频繁变动,导致系统状态的改变。

将所有的信息格式化为一个数据库的 SQL 查询的输出进行查看将会十分有益。想象一下,你能够像查询具有类似名称的 SQL 数据库表一样查询 psrpm 命令的输出。

幸运的是,有一个工具刚好实现了这个功能,而且功能更多:Osquery 是一个 开源的 “由 SQL 驱动的操作系统仪表、监控和分析框架”。

许多处理安全、DevOps、合规性的应用,以及仓储管理管理(仅举几例)在内部依赖 Osquery 提供的核心功能。

安装 Osquery

Osquery 适用于 Linux、macOS、Windows、FreeBSD。请按照 指南 为你的操作系统安装最新版本。(我会在下面的例子中使用 4.7.0 版本。)

安装完成后,确保 Osquery 可以工作:

$ rpm -qa | grep osquery
osquery-4.7.0-1.linux.x86_64
$
$ osqueryi --version
osqueryi version 4.7.0
$

Osquery 组件

Osquery 有两个主要组件:

  • osqueri 是一个交互式的 SQL 查询控制台,可以独立运行,不需要超级用户权限(除非要查询的表格需要访问权限)。
  • osqueryd 像一个安装在主机的监控守护进程,可以定期调度查询操作执行,从底层架构收集信息。

可以在不运行 osqueryd 的情况下执行 osqueri。另一个工具,osqueryctl,控制守护进程的启动、停止,并检查其状态。

$ rpm -ql osquery-4.8.0-1.linux.x86_64 | grep bin
/usr/bin/osqueryctl
/usr/bin/osqueryd
/usr/bin/osqueryi
$

使用 osqueryi 交互式命令提示符

你和 Osquery 的交互与使用 SQL 数据库十分相似。事实上,osqueryi 是 SQList shell 的一个修改版。执行 osqueryi 命令进入交互式命令提示符 ,就可以执行 Osquery 的命令,通常以 . 开始:

$ osqueryi
Using a virtual database. Need help, type '.help'
osquery>

要退出交互式命令提示符,执行 .quit 命令回到操作系统的命令提示符:

osquery>
osquery> .quit
$

找出可用的表

如前所述,Osquery 像 SQL 查询一样输出数据,数据库中的信息通常保存在表中。但是如何在不知道表名的情况下查询这些表呢?你可以运行 .tables 命令列出所有可以查询的表。如果你是一个 Linux 长期用户或者一个系统管理员 ,就会对表名十分熟悉,因为你一直在使用操作系统命令获取同样的信息:

osquery> .tables
  => acpi_tables
  => apparmor_events
  => apparmor_profiles
  => apt_sources

<<裁剪>>

  => arp_cache
  => user_ssh_keys
  => users
  => yara
  => yara_events
  => ycloud_instance_metadata
  => yum_sources
osquery>

检查各个表的模式

知道表名后,可以查看每个表提供的信息。既然 ps 命令经常用于获取进程信息,就以 processes 为例。执行 .schema 命令加上表名查看表中保存的信息。如果要验证命令返回的结果,可以快速执行 ps -efps aux,对比命令的输出和表中的内容:

osquery> .schema processes
CREATE TABLE processes(`pid` BIGINT, `name` TEXT, `path` TEXT, `cmdline` TEXT, `state` TEXT, `cwd` TEXT, `root` TEXT, `uid` BIGINT, `gid` BIGINT, `euid` BIGINT, `egid` BIGINT, `suid` BIGINT, `sgid` BIGINT, `on_disk` INTEGER, `wired_size` BIGINT, `resident_size` BIGINT, `total_size` BIGINT, `user_time` BIGINT, `system_time` BIGINT, `disk_bytes_read` BIGINT, `disk_bytes_written` BIGINT, `start_time` BIGINT, `parent` BIGINT, `pgroup` BIGINT, `threads` INTEGER, `nice` INTEGER, `is_elevated_token` INTEGER HIDDEN, `elapsed_time` BIGINT HIDDEN, `handle_count` BIGINT HIDDEN, `percent_processor_time` BIGINT HIDDEN, `upid` BIGINT HIDDEN, `uppid` BIGINT HIDDEN, `cpu_type` INTEGER HIDDEN, `cpu_subtype` INTEGER HIDDEN, `phys_footprint` BIGINT HIDDEN, PRIMARY KEY (`pid`)) WITHOUT ROWID;
osquery>

要进一步确认,可以使用下面的命令查看 RPM 包的结构信息,然后与操作系统命令 rpm -qarpm -qi 的输出比较:

osquery>
osquery> .schema rpm_packages
CREATE TABLE rpm_packages(`name` TEXT, `version` TEXT, `release` TEXT, `source` TEXT, `size` BIGINT, `sha1` TEXT, `arch` TEXT, `epoch` INTEGER, `install_time` INTEGER, `vendor` TEXT, `package_group` TEXT, `pid_with_namespace` INTEGER HIDDEN, `mount_namespace_id` TEXT HIDDEN, PRIMARY KEY (`name`, `version`, `release`, `arch`, `epoch`, `pid_with_namespace`)) WITHOUT ROWID;
osquery>

从 Osquery 的 表格文档 获取更多信息。

使用 PRAGMA 命令

或许模式信息对你来说太难看懂,还有另一种途径能够以详细的表格格式打印表中的信息:PRAGMA 命令。例如,我想通过 PRAGMA 用一种易于理解的格式查看 rpm_packages 表的信息:

osquery> PRAGMA table_info(rpm_packages);

这种表格式信息的一个好处是你可以关注想要查询的字段,查看命令提供的类型信息:

osquery> PRAGMA table_info(users);
+-----+-------------+--------+---------+------------+----+
| cid | name        | type   | notnull | dflt_value | pk |
+-----+-------------+--------+---------+------------+----+
| 0   | uid         | BIGINT | 1       |            | 1  |
| 1   | gid         | BIGINT | 0       |            | 0  |
| 2   | uid_signed  | BIGINT | 0       |            | 0  |
| 3   | gid_signed  | BIGINT | 0       |            | 0  |
| 4   | username    | TEXT   | 1       |            | 2  |
| 5   | description | TEXT   | 0       |            | 0  |
| 6   | directory   | TEXT   | 0       |            | 0  |
| 7   | shell       | TEXT   | 0       |            | 0  |
| 8   | uuid        | TEXT   | 1       |            | 3  |
+-----+-------------+--------+---------+------------+----+
osquery>

进行你的第一次查询

在你从表、模式、条目中获取到所有进行查询所需要的信息后,进行你的第一次 SQL 查询查看其中的信息。下面的查询返回系统中的用户和每个用户的用户 ID、组 ID、主目录和默认的命令行解释器。Linux 用户通过查看 /etc/passwd 文件的内容并执行 grepsedawk 命令获取同样的信息。

osquery>
osquery> select uid,gid,directory,shell,uuid FROM users LIMIT 7;
+-----+-----+----------------+----------------+------+
| uid | gid | directory      | shell          | uuid |
+-----+-----+----------------+----------------+------+
| 0   | 0   | /root          | /bin/bash      |      |
| 1   | 1   | /bin           | /sbin/nologin  |      |
| 2   | 2   | /sbin          | /sbin/nologin  |      |
| 3   | 4   | /var/adm       | /sbin/nologin  |      |
| 4   | 7   | /var/spool/lpd | /sbin/nologin  |      |
| 5   | 0   | /sbin          | /bin/sync      |      |
| 6   | 0   | /sbin          | /sbin/shutdown |      |
+-----+-----+----------------+----------------+------+
osquery>

不进入交互模式的查询

如果你想要在不进入 osqueri 交互模式的情况下进行查询,该怎么办?要用查询操作写命令行解释器脚本,这种方式可能十分有用。这种情况下,可以直接从 Bash 解释器 echo SQL 查询,通过管道输出到 osqueri

$ echo "select uid,gid,directory,shell,uuid FROM users LIMIT 7;" | osqueryi
+-----+-----+----------------+----------------+------+
| uid | gid | directory      | shell          | uuid |
+-----+-----+----------------+----------------+------+
| 0   | 0   | /root          | /bin/bash      |      |
| 1   | 1   | /bin           | /sbin/nologin  |      |
| 2   | 2   | /sbin          | /sbin/nologin  |      |
| 3   | 4   | /var/adm       | /sbin/nologin  |      |
| 4   | 7   | /var/spool/lpd | /sbin/nologin  |      |
| 5   | 0   | /sbin          | /bin/sync      |      |
| 6   | 0   | /sbin          | /sbin/shutdown |      |
+-----+-----+----------------+----------------+------+
$

获悉系统启动时开始的服务

Osquery 还可以列出系统启动时开始的所有服务。例如,可以查询 startup_items 表获取启动时开始的前五项服务的名称、状态和路径:

osquery> SELECT name,type,status,path FROM startup_items LIMIT 5;
  name = README
  type = Startup Item
status = enabled
  path = /etc/rc.d/init.d/README

  name = anamon
  type = Startup Item
status = enabled
  path = /etc/rc.d/init.d/anamon

  name = functions
  type = Startup Item
status = enabled
  path = /etc/rc.d/init.d/functions

  name = osqueryd
  type = Startup Item
status = enabled
  path = /etc/rc.d/init.d/osqueryd

  name = AT-SPI D-Bus Bus
  type = Startup Item
status = enabled
  path = /usr/libexec/at-spi-bus-launcher --launch-immediately
osquery>

查阅二进制文件的 ELF 信息

假如你想要弄清 ls 二进制文件的更多细节,通常会通过 readelf -h 命令,加上 ls 命令的路径。查询 Osquery 的 elf_info 表你可以得到同样的信息:

osquery> SELECT * FROM elf_info WHERE path="/bin/ls";
      class = 64
        abi = sysv
abi_version = 0
       type = dyn
    machine = 62
    version = 1
      entry = 24064
      flags = 0
       path = /bin/ls
osquery>

现在你应该初步了解如何使用 osqueri 查询自己想要的信息。然而,这些信息保存在数量巨大的表中;我查询过的一个系统中,有 156 个不同的表,这个数字可能是十分惊人的:

$ echo ".tables" | osqueryi | wc -l
156
$

要让事情变得更容易,可以从这些表开始获取你的 Linux 系统的信息:

系统信息表:

osquery> select * from system_info;

系统限制信息:

osquery> select * from ulimit_info;

由各种进程打开的文件:

osquery> select * from process_open_files;

系统上开放的端口:

osquery> select * from listening_ports;

运行中的进程信息:

osquery> select * from processes;

已安装的包信息:

osquery> select * from rpm_packages;

用户登录信息:

osquery> select * from last;

系统日志信息:

osquery> select * from syslog_events;

了解更多

Osquery 是一个强大的工具,提供了许多可以用于解决各种使用案例的主机信息。你可以阅读 文档 了解更多 Osquery 的信息。


via: https://opensource.com/article/21/6/osquery-linux

作者:Gaurav Kamathe 选题:lujun9972 译者:YungeG 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

抛开关于是否使用 JSON 作为配置格式的争论,只需学习如何用 Groovy 来解析它。

 title=

应用程序通常包括某种类型的默认或“开箱即用”的状态或配置,以及某种让用户根据自己的需要定制配置的方式。

例如,LibreOffice Writer 通过其菜单栏上的工具 > 选项,可以访问诸如用户数据、字体、语言设置等(以及更多的)设置。一些应用程序(如 LibreOffice)提供了一个点选式的用户界面来管理这些设置。有些,像 Tracker(GNOME 的“任务”,用于索引文件)使用 XML 文件。还有一些,特别是基于 JavaScript 的应用,使用 JSON,尽管它有许多人抗议(例如,这位作者这位其他作者)。

在这篇文章中,我将回避关于是否使用 JSON 作为配置文件格式的争论,并解释如何使用 Groovy 编程语言 来解析这类信息。Groovy 以 Java 为基础,但有一套不同的设计重点,使 Groovy 感觉更像 Python。

安装 Groovy

由于 Groovy 是基于 Java 的,它也需要安装 Java。你可能会在你的 Linux 发行版的软件库中找到最近的、合适的 Java 和 Groovy 版本。或者,你可以按照其网站上的 说明 安装 Groovy。 Linux 用户的一个不错的选择是 SDKMan,你可以使用它来获取 Java、Groovy 和许多其他相关工具的多个版本。 对于本文,我将使用我的发行版的 OpenJDK11 和 SDKMan 的 Groovy 3.0.7。

演示的 JSON 配置文件

在这个演示中,我从 Drupal 中截取了这个 JSON 文件,它是 Drupal CMS 使用的主要配置文件,并将其保存在文件 config.json 中:

{
 "vm": {
  "ip": "192.168.44.44",
  "memory": "1024",
  "synced_folders": [
   {
    "host_path": "data/",
    "guest_path": "/var/www",
    "type": "default"
   }
  ],
  "forwarded_ports": []
 },
 "vdd": {
  "sites": {
   "drupal8": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "[email protected]",
    "site_name": "Drupal 8",
    "site_mail": "[email protected]",
    "vhost": {
     "document_root": "drupal8",
     "url": "drupal8.dev",
     "alias": ["www.drupal8.dev"]
    }
   },
   "drupal7": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "[email protected]",
    "site_name": "Drupal 7",
    "site_mail": "[email protected]",
    "vhost": {
     "document_root": "drupal7",
     "url": "drupal7.dev",
     "alias": ["www.drupal7.dev"]
    }
   }
  }
 }
}

这是一个漂亮的、复杂的 JSON 文件,有几层结构,如:

<>.vdd.sites.drupal8.account_name

和一些列表,如:

<>.vm.synced_folders

这里,<> 代表未命名的顶层。让我们看看 Groovy 是如何处理的。

用 Groovy 解析 JSON

Groovy 自带的 groovy.json 包,里面有各种很酷的东西。其中最好的部分是 JsonSlurper 类,它包括几个 parse() 方法,可以将 JSON 转换为 Groovy 的 Map,一种根据键值存储的数据结构。

下面是一个简短的 Groovy 程序,名为 config1.groovy,它创建了一个 JsonSlurper 实例,然后调用其中的 parse() 方法来解析文件中的 JSON,并将其转换名为 configMap 实例,最后将该 map 输出:

import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

def config = jsonSlurper.parse(new File('config.json'))

println "config = $config"

在终端的命令行上运行这个程序:

$ groovy config1.groovy
config = [vm:[ip:192.168.44.44, memory:1024, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:[email protected], site_name:Drupal 8, site_mail:[email protected], vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:[email protected], site_name:Drupal 7, site_mail:[email protected], vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
$

输出显示了一个有两个键的顶层映射:vmvdd。每个键都引用了它自己的值的映射。注意 forwarded_ports 键所引用的空列表。

这很容易,但它所做的只是把东西打印出来。你是如何获得各种组件的呢?下面是另一个程序,显示如何访问存储在 config.vm.ip 的值:

import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

def config = jsonSlurper.parse(new File('config.json'))

println "config.vm.ip = ${config.vm.ip}"

运行它:

$ groovy config2.groovy
config.vm.ip = 192.168.44.44
$

是的,这也很容易。 这利用了 Groovy 速记,这意味着:

config.vm.ip

在 Groovy 中等同于:

config['vm']['ip']

configconfig.vm 都是 Map 的实例,并且都等同于在 Java 中的:

config.get("vm").get("ip")

仅仅是处理 JSON 就这么多了。如果你想有一个标准的配置并让用户覆盖它呢?在这种情况下,你可能想在程序中硬编码一个 JSON 配置,然后读取用户配置并覆盖任何标准配置的设置。

假设上面的配置是标准的,而用户只想覆盖其中的一点,只想覆盖 vm 结构中的 ipmemory 值,并把它放在 userConfig.json 文件中:

{
 "vm": {
  "ip": "201.201.201.201",
  "memory": "4096",
 }
}

你可以用这个程序来做:

import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

// 使用 parseText() 来解析一个字符串,而不是从文件中读取。
// 这给了我们一个“标准配置”
def standardConfig = jsonSlurper.parseText("""
{
 "vm": {
  "ip": "192.168.44.44",
  "memory": "1024",
  "synced_folders": [
   {
    "host_path": "data/",
    "guest_path": "/var/www",
    "type": "default"
   }
  ],
  "forwarded_ports": []
 },
 "vdd": {
  "sites": {
   "drupal8": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "[email protected]",
    "site_name": "Drupal 8",
    "site_mail": "[email protected]",
    "vhost": {
     "document_root": "drupal8",
     "url": "drupal8.dev",
     "alias": ["www.drupal8.dev"]
    }
   },
   "drupal7": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "[email protected]",
    "site_name": "Drupal 7",
    "site_mail": "[email protected]",
    "vhost": {
     "document_root": "drupal7",
     "url": "drupal7.dev",
     "alias": ["www.drupal7.dev"]
    }
   }
  }
 }
}
""")

// 打印标准配置
println "standardConfig = $standardConfig"

//读入并解析用户配置信息
def userConfig = jsonSlurper.parse(new File('userConfig.json'))

// 打印出用户配置信息
println "userConfig = $userConfig"

// 一个将用户配置与标准配置合并的函数
def mergeMaps(Map input, Map merge) {
  merge.each { k, v -&gt;
    if (v instanceof Map)
      mergeMaps(input[k], v)
    else
      input[k] = v
  }
}

// 合并配置并打印出修改后的标准配置
mergeMaps(standardConfig, userConfig)

println "modified standardConfig $standardConfig"

以下列方式运行:

$ groovy config3.groovy
standardConfig = [vm:[ip:192.168.44.44, memory:1024, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:[email protected], site_name:Drupal 8, site_mail:[email protected], vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:[email protected], site_name:Drupal 7, site_mail:[email protected], vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
userConfig = [vm:[ip:201.201.201.201, memory:4096]]
modified standardConfig [vm:[ip:201.201.201.201, memory:4096, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:[email protected], site_name:Drupal 8, site_mail:[email protected], vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:[email protected], site_name:Drupal 7, site_mail:[email protected], vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
$

modified standardConfig 开头的一行显示,vm.ip and vm.memory 的值被覆盖了。

眼尖的读者会注意到,我没有检查畸形的 JSON,也没有仔细确保用户的配置是有意义的(不创建新字段,提供合理的值,等等)。所以用这个递归方法来合并两个映射在现实中可能并不那么实用。

好吧,我必须为家庭作业留下 一些 东西,不是吗?

Groovy 资源

Apache Groovy 网站有很多很棒的 文档。另一个很棒的 Groovy 资源是 Mr. Haki。学习 Groovy 的一个非常好的理由是继续学习 Grails,它是一个非常高效的全栈 Web 框架,建立在 Hibernate、Spring Boot 和 Micronaut 等优秀组件之上。


via: https://opensource.com/article/21/6/groovy-parse-json

作者:Chris Hermansen 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

即使你用的是诸如 Gmail 的托管邮件服务,你也可以通过 Mutt 在终端里收发电子邮件。

 title=

我喜欢在 Linux 终端上读写电子邮件的便捷,因此我是 Mutt 这个轻量简洁的电子邮件客户端的忠实用户。对于电子邮件服务来说,不同的系统配置和网络接入并不会造成什么影响。这个客户端通常隐藏在我 Linux 终端的 某个标签页或者某个终端复用器的面板 上,需要用的时候随时可以调出来,不需要使用的时候放到后台,就不需要在桌面上一直放置一个电子邮件客户端的应用程序。

当今我们大多数人使用的都是托管电子邮件账号,在这种使用场景中并不会与电子邮件协议发生过多的直接交互。而 Mutt(以及更早的 ELM)是在更简单的时代创建的,那时候检查邮件只是对 uucp 的调用,以及对 /var/mail 的读取。当然 Mutt 也很与时俱进,随着各种流行的协议(如 POP、IMAP、LDAP)出现,它都实现了良好的支持。因此,即使我们使用的是 Gmail 这种邮件服务,也可以与 Mutt 无缝衔接。

如今在大多数情况下,用户都不会拥有自己的电子邮件服务器,大部分用户都会选择 Gmail,因此下文会以 Mutt + Gmail 为例作介绍。如果你比较注重电子邮件隐私,不妨考虑 ProtonMail 或者 Tutanota,它们都提供完全加密的电子邮件服务。其中 Tutanota 包含很多 开源组件,而 ProtonMail 则为付费用户提供 IMAP 桥接,简化了在非浏览器环境下的邮件访问。不过,很多公司、学校和组织都没有自己的电子邮件服务,而是使用 Gmail 提供的邮件服务,这样一来,大部分用户都会有一个 Gmail 邮箱。

当然,如果你自己就 拥有电子邮件服务器,那么使用 Mutt 就更简单了。下面我们开始介绍。

安装 Mutt

在 Linux 系统上,一般可以直接从发行版提供的软件库中安装 Mutt,另外需要在家目录中创建一个 .mutt 目录以存放配置文件:

$ sudo dnf install mutt
$ mkdir ~/.mutt

在 MacOS 上,可以通过 MacPorts 或者 Homebrew 安装;在 Windows 上则可以使用 Chocolatey 安装。

Mutt 是一个 邮件用户代理 Mail User Agent (MUA),因此它的作用是读取、编写以及向外部邮件池发送邮件。向邮件服务器实际传输邮件是其它应用或邮件服务的工作,尽管它们可以和 Mutt 进行协作,让我们看起来是 Mutt 完成了所有功能,但实际上并非如此。在弄懂了两者之间的区别之后,我们会对 Mutt 的配置更加清楚。

这也是为什么除了 Mutt 之外,我们还需要视乎进行通信的服务种类选择一些辅助应用程序。在本文中我使用的是 IMAP 服务,这可以让我本地的电子邮件副本与电子邮件服务提供商的远程邮件副本保持同步。如果你选择 POP 服务,配置的难度就更下一个台阶了,也无需依赖其它外部工具。我们需要 OfflineIMAP 这个 Python 应用程序来实现 IMAP 的集成,这个应用程序可以在 它的 GitHub 存储库 获取。

OfflineIMAP 目前仍然在从 Python 2 移植到 Python 3,目前需要手动安装,但以后你也可以通过 python3 -m pip 命令进行安装。

OfflineIMAP 依赖于 imaplib2 库,这个库也在努力开发当中,所以我更喜欢手动安装。同样地,也是通过 Git 将代码库克隆到本地,进入目录后使用 pip 安装。

首先安装 rfc6555 依赖:

$ python3 -m pip install --user rfc6555

然后从源码安装 imaplib2

$ git clone [email protected]:jazzband/imaplib2.git
$ pushd imaplib2.git
$ python3 -m pip install --upgrade --user .
$ popd

最后从源码安装 OfflineIMAP:

$ git clone [email protected]:OfflineIMAP/offlineimap3.git
$ pushd offlineimap3.git
$ python3 -m pip install --upgrade --user .
$ popd

如果你使用的是 Windows 上的 Cygwin,那么你还需要安装 Portlocker

配置 OfflineIMAP

OfflineIMAP 默认使用 ~/.offlineimaprc 这个配置文件,在它的代码库中会有一个名为 offlineimap.conf 的配置模板,可以直接将其移动到家目录下:

$ mv offlineimap3.git/offlineimap.conf ~/.offlineimaprc`

你可以使用任何文本编辑器打开浏览这个配置文件,它的注释很完善,便于了解各个可用的配置项。

以下是我的 .offlineimaprc 配置文件,为了清晰起见,我把其中的注释去掉了。对于你来说其中有些配置项的值可能会略有不同,但或许会为你的配置带来一些启发:

[general]
ui = ttyui
accounts = %your-gmail-username%
pythonfile = ~/.mutt/password_prompt.py
fsync = False

[Account %your-gmail-username%]
localrepository = %your-gmail-username%-Local
remoterepository = %your-gmail-username%-Remote
status_backend = sqlite
postsynchook = notmuch new

[Repository %your-gmail-username%-Local]
type = Maildir
localfolders = ~/.mail/%your-gmail-username%-gmail.com
nametrans = lambda folder: {'drafts':  '[Gmail]/Drafts',
                            'sent':    '[Gmail]/Sent Mail',
                            'flagged': '[Gmail]/Starred',
                            'trash':   '[Gmail]/Trash',
                            'archive': '[Gmail]/All Mail',
                            }.get(folder, folder)

[Repository %your-gmail-username%-Remote]
maxconnections = 1
type = Gmail
remoteuser = %your-gmail-username%@gmail.com
remotepasseval = '%your-gmail-API-password%'
## remotepasseval = get_api_pass()
sslcacertfile = /etc/ssl/certs/ca-bundle.crt
realdelete = no
nametrans = lambda folder: {'[Gmail]/Drafts':    'drafts',
                            '[Gmail]/Sent Mail': 'sent',
                            '[Gmail]/Starred':   'flagged',
                            '[Gmail]/Trash':     'trash',
                            '[Gmail]/All Mail':  'archive',
                            }.get(folder, folder)
folderfilter = lambda folder: folder not in ['[Gmail]/Trash',
                                             '[Gmail]/Important',
                                             '[Gmail]/Spam',
                                             ]

配置文件里有两个可以替换的值,分别是 %your-gmail-username%%your-gmail-API-password%。其中第一个值需要替换为 Gmail 用户名,也就是邮件地址中 @gmail.com 左边的部分。而第二个值则需要通过双因素身份验证(2FA)后从 Google 获取(即使你在查收邮件时不需要使用 2FA)。

为 Gmail 设置双因素身份验证(2FA)

Google 希望用户通过 Gmail 网站收发电子邮件,因此当你在 Gmail 网站以外操作电子邮件时,实际上是被 Google 作为“开发者”看待(尽管你没有进行任何开发工作)。也就是说,Google 会认为你正在创建一个应用程序。要获得开发者层面的应用程序密码,就必须设置双因素身份验证。完成了这个过程以后,就可以获得一个应用程序密码,Mutt 可以通过这个密码在浏览器以外的环境登录到你的电子邮箱中。

为了安全起见,你还可以在 Google 的 账号安全 页面中添加一个用于找回的电子邮件地址。

在账号安全页面中,点击“ 两步验证 2-step Verification ”开始设置 2FA,设置过程中需要用到一部手机。

激活 2FA 之后,账号安全页面中会出现“ 应用程序密码 App Passwords ”选项,点击就可以为 Mutt 创建一个新的应用程序密码。在 Google 生成密码之后,将其替换 .offlineimaprc 配置文件中的 %your-gmail-API-password% 值。

直接将应用程序密码记录在 .offlineimaprc 文件中,这种以纯文本形式存储的做法有一定的风险。长期以来我都是这样做的,而且感觉良好,因为我的家目录是加密的。但出于安全考虑,我现在已经改为使用 GnuPG 加密应用程序密码,这部分内容不在本文的讨论范围,关于如何设置 GPG 密码集成,可以参考我的 另一篇文章

在 Gmail 启用 IMAP

在你永远告别 Gmail 网页界面之前,还有最后一件事:你必须启用 Gmail 账户的 IMAP 访问。

在 Gmail 网站页面中,点击右上角的“cog”图标,选择“ 查看所有设置 See all settings ”。在 Gmail 设置页面中,点击“POP/IMAP”标签页,并选中“ 启用 IMAP enable IMAP ”,然后保存设置。

现在就可以在浏览器以外访问你的 Gmail 电子邮件了。

配置 Mutt

Mutt 的配置过程相对简单。和 .bashrc.zshrc.emacs 这些配置文件一样,网络上有很多优秀的 .muttrc 配置文件可供参照。我自己的 .muttrc 配置文件则借鉴了 Kyle RankinPaul Frields 等人的配置项和想法。下面列出我的配置文件的一些要点:

set ssl_starttls=yes
set ssl_force_tls=yes

set from='[email protected]'
set realname='Tux Example'

set folder = imaps://imap.gmail.com/
set spoolfile = imaps://imap.gmail.com/INBOX
set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
set smtp_url="smtp://smtp.gmail.com:25"
set move = no
set imap_keepalive = 900
set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"

# Paths
set folder           = ~/.mail
set alias_file       = ~/.mutt/alias
set header_cache     = "~/.mutt/cache/headers"
set message_cachedir = "~/.mutt/cache/bodies"
set certificate_file = ~/.mutt/certificates
set mailcap_path     = ~/.mutt/mailcap
set tmpdir           = ~/.mutt/temp
set signature        = ~/.mutt/sig
set sig_on_top       = yes

# Basic Options
set wait_key = no
set mbox_type = Maildir
unset move               # gmail does that

# Sidebar Patch
set sidebar_visible = yes
set sidebar_width   = 16
color sidebar_new color221 color233

## Account Settings
# Default inbox
set spoolfile = "+example.com/INBOX"

# Mailboxes to show in the sidebar.
mailboxes +INBOX \
          +sent \
          +drafts

# Other special folder
set postponed = "+example.com/drafts"

# navigation
macro index gi "<change-folder>=example.com/INBOX<enter>" "Go to inbox"
macro index gt "<change-folder>=example.com/sent" "View sent"

整个配置文件基本是开箱即用的,只需要将其中的 Tux Exampleexample.com 替换为你的实际值,并将其保存为 ~/.mutt/muttrc 就可以使用了。

启动 Mutt

在启动 Mutt 之前,需要先启动 offlineimap 将远程邮件服务器上的邮件同步到本地。在首次启动的时候耗时可能会比较长,只需要让它整晚运行直到同步完成就可以了。

在同步完成后,启动 Mutt:

$ mutt

Mutt 会提示你打开用于管理电子邮件的目录权限,并展示收件箱的视图。

 title=

学习使用 Mutt

在学习使用 Mutt 的过程中,你可以找到最符合你使用习惯的 .muttrc 配置。例如我的 .muttrc 配置文件集成了使用 Emacs 编写邮件、使用 LDAP 搜索联系人、使用 GnuPG 对邮件进行加解密、链接获取、HTML 视图等等一系列功能。你可以让 Mutt 做到任何你想让它做到的事情,你越探索,就能发现越多。


via: https://opensource.com/article/21/7/gmail-linux-terminal

作者:Seth Kenlon 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Zlib 是一个用于数据压缩的开源库。

作为使用者,你可能会遇到需要安装 zlib(或 zlib-devel 包)作为另一个应用程序的依赖项的情况。

但问题来了,如果你尝试在 Ubuntu 上安装 zlib,它会抛出 “unable to locate package zlib” 错误。

sudo apt install zlib
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package zlib

为什么会看到这个 Ubable to locate package 错误呢?因为没有名为 zlib 的包。

如果你 使用 apt search 命令,你会发现有几个包可以让你安装:zlib 1g 和 zlib 1g-dev。当你知道这些后,只需一个 apt 命令就可以安装它们。

在基于 Ubuntu 的 Linux 发行版上安装 Zlib

打开终端,使用以下命令:

sudo apt install zlib1g

请记住 g 前面的字母是数字 1,而不是小写的字母 L。很多人在输入命令时都会犯这个错误。

另一个包,zlib 1g-dev 是开发包。只有在你需要时才安装它,否则你应该使用 zlib 1g 包。

sudo apt install zlib1g-dev

你也可以 Zlib 网站 下载源代码并安装它。但是,除非你有充分的理由,否则我不推荐使用源代码方式来安装 zlib。例如,如果你需要最新或特定版本的 zlib,但该版本在发行版的仓库中不可用。

有趣的是,像安装 zlib 这样看似很小的东西可能会变得很麻烦,有两个原因:一个是不同的包名;另一个是包含“隐藏”数字 1,它与小写 L 混淆了。

我希望这个快速提示能帮助到你。随意在评论部分留下你的问题、建议或简单的一句 “thank you”。


via: https://itsfoss.com/install-zlib-ubuntu/

作者:Abhishek Prakash 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

虽然有一个 FreeDOS 版的 tar,但 DOS 上事实上的标准归档工具是 Zip 和 Unzip。

 title=

在 Linux 上,你可能熟悉标准的 Unix 归档命令:tar。FreeDOS 上也有 tar 的版本(还有其他一些流行的归档程序),但 DOS 上事实上的标准归档程序是 Zip 和 Unzip。Zip 和 Unzip 都默认安装在 FreeDOS 1.3 RC4 中。

Zip 文件格式最初是由 PKWARE 的 Phil Katz 在 1989 年为 PKZIP 和 PKUNZIP 这对 DOS 归档工具构思的。Katz 将 Zip 文件的规范作为一个开放标准发布,因此任何人都可以创建 Zip 档案。作为开放规范的结果,Zip 成为 DOS 上的一个标准归档格式。Info-ZIP 项目实现了一套开源的 ZIPUNZIP 程序。

对文件和目录进行压缩

你可以在 DOS 命令行中使用 ZIP 来创建文件和目录的归档。这是一个方便的方法,可以为你的工作做一个备份,或者发布一个“包”,在未来的 FreeDOS 发布中使用。例如,假设我想为我的项目源码做一个备份,其中包含这些源文件:

 title=

我想把这些文件归档

ZIP 有大量的命令行选项来做不同的事情,但我最常使用的命令行选项是 -r 来处理目录和子目录 递归,以及使用 -9 来提供可能的最大压缩。ZIPUNZIP 使用类似 Unix 的命令行,所以你可以在破折号后面组合选项:-9r 将提供最大压缩并在 Zip 文件中包括子目录。

 title=

压缩一个目录树

在我的例子中,ZIP 能够将我的源文件从大约 33KB 压缩到大约 22KB,为我节省了 11KB 的宝贵磁盘空间。你可能会得到不同的压缩率,这取决于你给 ZIP 的选项,或者你想在 Zip 文件中存储什么文件(以及有多少)。一般来说,非常长的文本文件(如源码)会产生良好的压缩效果,而非常小的文本文件(如只有几行的 DOS “批处理”文件)通常太短,无法很好地压缩。

解压文件和目录

将文件保存到 Zip 文件中是很好的,但你最终会需要将这些文件解压到某个地方。让我们首先检查一下我们刚刚创建的 Zip 文件里有什么。为此,使用 UNZIP命令。你可以在 UNZIP中使用一堆不同的选项,但我发现我只使用几个常用的选项。

要列出一个 Zip 文件的内容,使用 -l (“list”) 选项。

 title=

用 unzip 列出归档文件的内容

该输出允让我看到 Zip 文件中的 14 个条目:13 个文件加上 SRC 目录。

如果我想提取整个 Zip 文件,我可以直接使用 UNZIP 命令并提供 Zip 文件作为命令行选项。这样就可以从我当前的工作目录开始提取 Zip 文件了。除非我正在恢复某个东西的先前版本,否则我通常不想覆盖我当前的文件。在这种情况下,我希望将 Zip 文件解压到一个新的目录。你可以用 -d (“destination”) 命令行选项指定目标路径。

 title=

你可以用 -d 来解压到目标路径

有时我想从一个 Zip 文件中提取一个文件。在这个例子中,假设我想提取一个 DOS 可执行程序 TEST.EXE。要提取单个文件,你要指定你想提取的 Zip 文件的完整路径。默认情况下,UNZIP 将使用 Zip 文件中提供的路径解压该文件。要省略路径信息,你可以添加 -j(“junk the path”) 选项。

你也可以组合选项。让我们从 Zip 文件中提取 SRC\TEST.EXE 程序,但省略完整路径并将其保存在 TEMP 目录下:

 title=

unzip 组合选项

因为 Zip 文件是一个开放的标准,所以我们会今天继续看到 Zip 文件。每个 Linux 发行版都可以通过 Info-ZIP 程序支持 Zip 文件。你的 Linux 文件管理器可能也支持 Zip 文件。在 GNOME 文件管理器中,你应该可以右击一个文件夹并从下拉菜单中选择“压缩”。你可以选择创建一个包括 Zip 文件在内的新的归档文件。

创建和管理 Zip 文件是任何 DOS 用户的一项关键技能。你可以在 Info-ZIP 网站上了解更多关于 ZIPUNZIP 的信息,或者在命令行上使用 h(“帮助”)选项来打印选项列表。


via: https://opensource.com/article/21/6/archive-files-freedos

作者:Jim Hall 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出