移除 macOS 中被企业策略强制安装的 Chrome 插件扩展的方法

公司配发的 Macbook 安装了一些监控软件,毕竟是办公设备,这点倒是无可厚非。但是,其中的 Forcepoint DLP Endpoint 会向日常使用的主力浏览器 Chrome 中安装一个 WebsenEndpoint 的扩展插件。

这个插件的作用不必多说,但是有一个副作用就是让 Chrome 无法自动填写任何网站用户名密码。每天要输入上百次的密码这种体力活是绝对不能忍受的。于是尝试卸载这个插件。但是这个插件是使用企业策略 (Installed by enterprise policy) 强制安装,无法在Chrome中下载。但是可以通过将与之关联的 Profile 删除实现卸载的作用:

但是过两天,Forcepoint 又会把这个插件装回来😂 不过没关系,我们有的是办法。

方法一:通过占用 Chrome 插件文件位置,防止真正插件重新装回

原理是这样的:Chrome 的插件安装在 ~/Library/Application Support/Google/Chrome/Default/Extensions 目录下:

除去 Temp, 每个文件夹对应一个插件。我们希望移除的插件的文件夹名称是 kmofofmjgmakbbmngpgmehldlaaafnjn。由于 macOS 文件夹下,相同名称的文件和文件夹只能存在一个。因此,我们只需要在插件删除以后,在这个目录下新建一个名称为 kmofofmjgmakbbmngpgmehldlaaafnjn 的空文件:

然后,再通过文件系统的 Lock 功能锁定改文件,防止该文件被 Forcpoint 删除:

至此,大功告成,so easy!

方法二:修改 Forcepoint DLP Endpoint 插件安装脚本,禁止强奸 Chrome

法一虽然可以防止Chrome被重新安装插件,但是过几天以后,你会在你的 Profiles 配置下发现,虽然 Chrome 插件安装失败了,但是依然会成功安装这个 Profile:

虽然不会干扰系统的任何功能,但是估计很多强迫症患者看到这个还是挺难受的……从图中我们可以看到,这个插件的路径在 /Library/Application Support/Websense Endpoint/DLP:

其中 setup_chrome_ext.sh 就是强插 Chrome 的脚本:

脚本写得简单粗暴:通过 $PROFILES -I -F "/Library/Application Support/Websense Endpoint/DLP/WebsenseEndpointExtension.config" 向系统强行安装 profile. 要防止其安装插件,把这行代码删除即可。但是,这个文件是属于 admin 用户组的,我们平时使用的账号,即使集合 sudo 也只是 wheel 用户组,是干不过 admin 的,导致我们无法在正常模式下编辑该文件:

因此,我们需要通过 Command (⌘)-R 重启到恢复模式,然后在 /Volumes/mac.os/Library/Application Support/Websense Endpoint/DLP 目录下,将对应代码删除即可。

至此,自己基本满意了🤔

后记

稍微浏览了一下 /Library/Application Support/Websense Endpoint 文件夹,发现其实这个软件不仅强插 Chrome, 还会强插 FireFox:

艾玛……proxy…吓死宝宝了,已经不想改脚本了。直接在恢复模式下删除文件,然后用方法一的方法,建了一个 Lock 文件锁定这个位置。什么,还有 upgrade.sh? 你怎么不上天呢,也一并删除了……突然想起,自己在无所不能的恢复模式下,要不整个软件一起删除了?想到隔天IT技术小哥可能过来找麻烦,就此打住吧😂

基于 Golang AST 自动生成建表 sql

写后台业务的同学经常调侃自己的工作就是围绕数据表CRUD. 虽然实际工作并不会如此简单,但是日常中的确有很多类似的重复、缺乏创造性的工作。而这种工作上是可以在一定程度上自动化的。为了提供业务研发人员开发效率,前段时间我们开发了一个后端开发工作流工具,主要提供以下功能:

  • 生成服务器API基础代码以及Swagger文档注释 (只支持gin框架)
  • 生成服务器API客户端代码
  • go struct 批量添加 tag
  • 生成 gorm model struct
  • model struct 生成 sql

因为这些功能跟我们内部的公共库有一定耦合,因此整个工具可能无法开源出来。这里,我们以model struct 生成 sql功能为例,聊聊我们在做这个工具的思路和使用到的工具。

任务

这里以我们在项目中使用的jinzhu同学的gorm作为orm库。如果你在使用golang的其他orm lib,实现方式应该大同小异。

我们的任务是从下面的这个model struct定义:

生成 mysql 建表语句(文件):

思路

model struct 生成 sql是一个将语言A翻译为语言B的问题。而这个过程跟我们平时将源代码编译为二进制可执行程序从原理上说是没有区别的。因此,这个问题本质上是一个编译问题。一个完整的编译包含以下步骤:

对于本文要完成的任务来说,主要完成词法分析、语法分析、目标代码生成即可。

工具

要完成词法分析和语法分析,我们有上古神器 LexYacc, Yet Another Compiler-Compiler. 而我们只是想完成一个建表文件的生成任务而已,使用者两个工具有时候要自定义语法,又是要自己写lex和yacc文件,累觉不爱……

Golang 有很多其他语言羡慕不来的工具,例如 go pprof, go list, go vet 等。在语言元编程方面,go 1.4实现了自举;而编译时候涉及到的词法分析和语法分析很早前就放在了标准库 go/ast 中。AST是abstract syntax tree的缩写,直译过来是抽象语法树。通过AST,我们可以编写一个go程序解析go源代码。具体到本文要完成的任务,要编写一个这样的程序解析定义数据表的model struct, 然后生成sql建表语句。

实现

具体到我们的任务实现,可以拆分为如下几个步骤:

  • 加载源代码,生成 AST Tree
  • 获取和解析 model struct AST
  • 根据struct field name/tag 生成create_definition, table_options

完整代码实现,可以移步github gorm2sql.

实现效果:

user_email.go:

type UserBase struct {
    UserId string `sql:"index:idx_ub"`
    Ip     string `sql:"unique_index:uniq_ip"`
}

type UserEmail struct {
    Id       int64    `gorm:"primary_key"`
    UserBase
    Email      string
    Sex        bool
    Age        int
    Score      float64
    UpdateTime time.Time `sql:"default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"`
    CreateTime time.Time `sql:"default:CURRENT_TIMESTAMP"`
}
gorm2sql sql -f user_email.go -s UserEmail -o db.sql

Result:

CREATE TABLE `user_email`
(
  `id` bigint AUTO_INCREMENT NOT NULL ,
  `user_id` varchar(128) NOT NULL ,
  `ip` varchar(128) NOT NULL ,
  `email` varchar(128) NOT NULL ,
  `sex` boolean NOT NULL ,
  `age` int NOT NULL ,
  `score` double NOT NULL ,
  `update_time` datetime NOT NULL  DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `create_time` datetime NOT NULL  DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_ub (`user_id`),
  UNIQUE INDEX uniq_ip (`ip`),
  PRIMARY KEY (`id`)
) engine=innodb DEFAULT charset=utf8mb4;

扩展阅读

Yet Another GeoIP Alfred Workflow

Yet Another GeoIP Alfred Workflow

在浏览网站以及在选线路的时候,经常会习惯性的查看一下对方的IP及地理位置信息. 师兄的 ip.cn 以及 ipip.net 都是不错的选择。但无奈自己是小帽子 Alfred 控,本着少做体力活的原则,写了一个 Workflow.

ip me 查看本地的外网ip及位置信息

ip domain 查看域名ip及位置信息

ip url 查看url中域名ip及位置信息

如果觉得你也有这样需求,可以在这里下载,enjoy!

References

  • http://www.deanishe.net/alfred-workflow

GitLab搭建笔记

GitLab搭建笔记

GitLab使用Omnibus package搭建是分分钟就可以搞定的事情,但是我搭建的GitLab服务:

  1. 服务器在墙内;
  2. 服务器在一个路由器后面;

因此,浪费了一个晚上时间才把几分钟计划完成的事情搞定。这里给遇到类似情况的程序员做个简单的笔记,希望可以为他们节约一点时间吧。

服务器在墙内

Omnibus package(大小约340MB)通过AWS S3(AWS Region为美国新泽西)进行分发。墙内下载该package的速度极慢(电信百兆宽带下载速度约8KB/S),且部分时间段packages-gitlab-com.s3.amazonaws.com域名疑似被污染(四川成都地区)。因此,只好通过墙外的VPS中转下载。当前最新版(2015.08.30)为gitlab-ce_7.14.1-ce.0_amd64.deb. 上传了一份到百度网盘, 密码: qf38。阅兵在即,墙外要中转一个文件进来真是浪费生命,唉…

服务器在路由器后

这个比较好解决,需要映射两个端口。

  1. 映射Web端口: 映射路由器外部GitLab端口到GitLab配置端口(/etc/gitlab/gitlab.rb external_url ‘http://your-host:PORT’ );
  2. 映射SSH端口: 映射路由器外部GitLab SSH端口到22端口, 然后修改/etc/gitlab/gitlab.rb文件:
    • gitlab_rails[‘gitlab_shell_ssh_port’] = 路由器外部GitLab SSH端口
    • 注意:gitlab_rails[‘gitlab_shell_ssh_port’]只是配置代码库地址的端口,不会修改SSH真实使用的端口。
  3. sudo gitlab-ctl reconfigure

正则表达式给力小伙伴

7~8年前,很多人会告诉你「不会C++的程序员不算是真正的程序员」,现在看到这句话的你可能会忍俊不禁,但的确是那个「桌面软件时代」的事实。如今,又有一句非常有意思的话出现得越来越频繁「不会正则表达式处理字符串的程序员不是好前端」。Anyway, 这里不讨论语言优劣,更不掺和程序员的「评价标准」。借这个话题向大家推荐一个非常给力的「正则表达式在线学习、编写、测试的工具」:RegExr

据我观察,很多人在处理字符串的时候,在特定字符串函数(如strpos, str_search)与正则表达式之间,往往选择前者。除去部分简单场景的确适合使用特定字符串处理函数,很多人其实是因为思维/学习惰性,根本不去想怎样用正则表达式「更加优雅」的处理手上的问题。甚至有些人宁愿用str*函数族写好几十行且不完备的字符串处理代码也不尝试用正则表达式。每当看到这样的程序小猿,我就会毫不犹豫的向他们推荐RegExr。RegExr给力之处体现在一下几个方面:

  1. 极快的页面加载速度。在这之前,我使用过一些其他的正线正则表达式工具,但是加载速度都没有RegExr快。
  2. 极简的在线帮助。让你不再畏难学习正则表达式。这点很重要,想想你身边有多少人学习正则表达式不了了之吧。
  3. 典型够用的实例。
  4. 资源丰富的社区。直接搜索常用的正则表达式,节约时间,避免重新发明轮子。
  5. 实用的收藏/保存功能。收藏、保存自己常用的一些正则表达式。
  6. 实时的响应,酷炫的tip提示。编写表达式时,系统会实时执行该表达式进行字符串匹配。在表达式和匹配的字符串上都会给出非常友好的tip。
  7. 两分钟入门,好吧,其实是2’45”:

另外,作者Grant Skinne是一个非常乐于分享的家伙,在GitHub上可以找到这个项目的源代码,有兴趣的童鞋可以自己研究一下。我才不会告诉你「只有研究了RegExr的源代码的程序员才算会处理字符串的程序员」呢。