Thursday, March 21, 2019

在Pull requests上添加commits

自己的Pull requests, 在Pull requests后, 如何再次添加commits上去

Pull requests是绑定你Pull requests的那个分支的, 所以说只要你push commits到你Pull requests上的那个分支就可以了
比如, 你在分支patch-1上修改了内容, 然后Pull requests到别人的仓库, 接下来, 你想继续修改, 直接commits到patch-1这个分支即可

如何添加commits到别人的Pull requests上

只要Contributor没有取选Allow edits from maintainers就可以修改, 一般情况没人会取选

第一种方式: 通过网页来修改

非常简单, 点进commit里去, 右上角有个像笔一样的图标直接点进去修改提交即可

第二种方式: 通过命令行来修改

这个问题我一直想解决, Google了很多, 都没有发现有详细解决的
首先明确一点, 如果说Contributor没有取选Allow edits from maintainers, 那么默认maintainers 就可以修改Pull requests绑定的那一个分支
这样的话, 直接提交到那个分支即可
这里写下自己的命令, 使用了hub, 比用git省很多事, 不用复制用户名, 分支名啥的

1
2
3
4
hub pr list        # 列出PR
hub pr checkout xx # 要切换到的PR
xxx                # 这里修改然后commit
hub push           # push
这样就可以了

Monday, January 7, 2019

使用gpg钥对ssh进行认证

使用gpg钥对ssh进行认证

1. 生成gpg认证私钥


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
❯ gpg --expert --edit-key your_id                                    ## 使用专家模式, 不然没有认证的选项
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa2048/7DEFA5351BCE3C55
     created: 2019-01-07  expires: 2021-01-06  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa2048/2FCE923F8ECB63F6
     created: 2019-01-07  expires: 2021-01-06  usage: E
[ultimate] (1). hhhhh <h@mail.com>

gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
Your selection? 8                                                   ## 选8, RSA, 自定义权限

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt                               ## 这里显示默认有Sign和Encrypt两种权限

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S                                                   ## 关闭Sign

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? E                                                   ## 关闭Encrypt

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A                                                   ## 开启Authenticate

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q                                                    ## 退出
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y                                             ## 有效期
Key expires at Tue Jan  7 11:33:54 2020 CST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa2048/7DEFA5351BCE3C55
     created: 2019-01-07  expires: 2021-01-06  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa2048/2FCE923F8ECB63F6
     created: 2019-01-07  expires: 2021-01-06  usage: E
ssb  rsa4096/19D32A8839DCAA1F
     created: 2019-01-07  expires: 2020-01-07  usage: A
[ultimate] (1). hhhhh <h@mail.com>

gpg> save                                                            ## 保存

2. 文件配置


1
2
3
export GPG_TTY=$(tty)
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
echo UPDATESTARTUPTTY | gpg-connect-agent 1> /dev/null
加入你的bashrc

1
enable-ssh-support
加入~/.gnupg/gpg-agent.conf

1
2
3
4
5
6
7
8
9
10
11
❯ gpg -k --with-keygrip
/Users/root/.gnupg/pubring.kbx
-----------------------------
pub   rsa2048 2019-01-07 [SC] [expires: 2021-01-06]
      8A9FC025A44AA4824C1F4AE27DEFA5351BCE3C55
      Keygrip = BEFCCDFE36CC5442B888B8459265C68B60A4ABD2
uid           [ultimate] hhhhh <h@mail.com>
sub   rsa2048 2019-01-07 [E] [expires: 2021-01-06]
      Keygrip = 422922ACFD099E79863D93B93333528F225C90FC
sub   rsa4096 2019-01-07 [A] [expires: 2020-01-07]
      Keygrip = 999A87A51CFE82DAA494BEB42F585051307F9E33
选择你新加的带有[A]标志的那个, 即999A87A51CFE82DAA494BEB42F585051307F9E33
加入到~/.gnupg/sshcontrol
运行ssh-add -l, 查看是否有加入
接下来运行gpg --export-ssh-key yourid导出ssh key放到你的服务器上的~/.ssh/authorized_keys中
重启shell, 就可以连接了

Reference

Sunday, January 6, 2019

一些关于gpg的问题

一些关于gpg的问题, 是自己在使用gpg中产生的疑问.
在搜索的时候发现, 就中文资料是基本上没有, 只有英文资料…

1. gpg显示的密钥信息都什么意思?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
❯ gpg -K
/Users/root/.gnupg/pubring.kbx
-----------------------------
sec   rsa4096 2017-11-22 [SC]
      CFED195E075BE71B221A2432315F3A656223B79B
uid           [ unknown] comwrg <xcomwrg@gmail.com>
ssb   rsa4096 2017-11-22 [E]


~ master*
❯ gpg -k
/Users/root/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096 2017-11-22 [SC]
      CFED195E075BE71B221A2432315F3A656223B79B
uid           [ unknown] comwrg <xcomwrg@gmail.com>
sub   rsa4096 2017-11-22 [E]

sec, uid, ssb, pub, sub 的意思

sec, SECret key, 表明是私钥
uid, 拥有者的信息, 姓名和邮箱
ssb, Secret SuBkey, 子私钥
pub, PUBlic key, 表明是公钥
sub, public SUBkey, 子公钥

[SC] 和 [E] 的意思

S, Sign, 表示可以用来签名
C, Certify, 表示可以用来验证签名
E, Encrypt, 表示可以用来加密
A, Authentication, 表示可以用来认证
所以[SC]的意思就是这个钥可以用来签名和验证签名
同样[E]的意思表示这个钥可以用来加密

2. 子钥是什么?

我们看主私钥的标志是[SC], 代表了主钥只可以签名和验证签名, 那为什么不可以加密呢?
然后我们在看子钥的标志是[E], 表示可以加密
这样的话, 其实gpg最基本的结构其实就仅仅只有主钥, 这个主钥有签名和验证签名两个功能, 在加入子钥的时候, 主钥会对子钥签名, 这样就可以保证这个子钥是属于这个主钥的
在这样的逻辑结构下, 我们就可以加入子钥了, 并可以给予子钥相应的权限
不过, 为什么话说回来, 为什么需要子钥呢, 直接一个主钥不就可以了吗?
具体参考https://wiki.debian.org/Subkeys 这里说明了为什么需要子钥匙
有很多的好处, 由于主钥和子钥是分离的, 我们可以通过主钥来撤销子钥, 以及延长子钥的过期时间通过主钥(假如就一个钥匙的话, 肯定无法做到), 等等

3. gpg如何判断过期的

这个问题,,,我想错方向了, 一开始我想的是这个gpg如何阻止签名的, 这个时间可以伪造啊, 后来一想, 不对啊, 就算你在过期的时间签名了, 但是别人那里会显示过期的…

4. gpg私钥泄露了, 我该这么办

刚开始接触的gpg的时候, 其实自己就想问这个问题了
大概就是向私钥服务器发布撤销证书吧
如果是子私钥泄露了, 就撤销子钥, 这个损失其实不是很大
如果是主私钥泄露了, 就撤销主钥, 这个大概是凉凉的节奏

5. 如果保证私钥的安全

这个问题我也一直在思考, 就现在的开发环境下, 如果保证自己的电脑用的软件没有后门, 因为日常实在是要安装和用到太多太多的软件了, 没办法确保安全, 除非断网开发… 而且, 经过我的测试, 脚本是可以直接执行gpg --export-secret-keys的, 个人认为有两种办法
  1. 保证主私钥的安全, 把主私钥隔离起来, 只在绝对安全的主机内导入主私钥
  2. 给私钥上passphrase, 这样就算拷贝走, 也没发直接用

Reference


Thursday, December 27, 2018

c++右值引用




右值引用是c++11提出的, 还真难搞懂, 花了不少的时间找资料

背景

先需要知道什么是左值什么是右值
简单的来说 左值 出现在等号的左边和右边
右值 只能出现在等号的右边, 不能出现在等号的左边

令一种区分左值和右值的办法是取地址符, 只有左值可以被取地址, 右值无法被取地址
所以, 右值是一些常量和一些临时变量, 没有名字
左值是一些有名字的变量
要想要搞懂右值引用就要明白右值引用的出现是来解决什么问题的
可以看这里 https://www.zhihu.com/question/22111546
里面讲的非常明白, 关于右值引用出现的缘由

move()

move() 的作用将右值利用起来, 不被浪费
比如一个函数返回了一个占用内存非常大的变量, 在c++中这样势必会出现拷贝的开销
比如



1
2
3
4
5
6
7
8
struct st {
    int arr[10000];
}

st foo() {
    st s;
    return s;
}
如果运行st s = foo(); 势必会拷贝一份给s, 再将临时变量删除
假如想避免这种情况, 可以考虑用指针, const st & 这样的返回值, 这又导致了动态分配内存, 大家都不想动不动就动态分配内存吧, 手动释放内存需要考虑太多东西了
所以, 你看可不可以延长临走变量的生命周期呢, 直接将变量s直接指向临时变量的内存呢, 即函数foo()中的s的那片内存
嗯, 肯定可以啊, 这就是move()的作用所在
所以, 原来的函数可以这么写



1
2
3
4
st &&foo() {
    st s;
    return std::move(s);
}
然后可以运行st &&s = foo(); 这样就可以完美解决
又比如



1
2
3
4
5
6
7
std::vector<int> tmp(10000);

std::vector<std::vector<int>> v;

v.push_back(tmp);

// 接下来变量tmp就不用了
在这样的情况下, tmp拷贝到v中是不是又感觉有点浪费呢, 因为tmp不再使用, 所以可以写成v.push_back(std::move(tmp));
这样又节省了复制的开销

forward()

这个又是干啥的呢, 一开始接触的我一脸懵逼.
总的来说, forward为了区分一个参数被传进来, 他到底是左值还是右值, 然后去调用相应的函数
比如



1
2
3
4
5
6
7
void f(int &i) {  }
void f(int &&i) {  }

template<class T>
void foo(T &&t) {
    f(t);
}
这样的代码, 我调用函数foo()去传进去一个右值, 到了函数foo()中, 参数t就是左值, 因为t是有名字的, 所以不管这么调用f(t) 都会去调用 f(int &i) 这个函数
所以这个时候需要去区分左值还是右值, 可以这么写 f(std::forward<T>(t)), forward会自动转发到相应的函数
关于上面的代码, 你可能会有个疑问就是 foo(T &&t) 为什么可以传左值?
嗯, 就这个问题, 我也懵逼了, 不过查了半边资料, 加上在stackoverflow上提问, 终于终于找到了答案
对于C++语言,不可以在源程序中直接对引用类型再施加引用。T& &将编译报错。C++11标准中仍然禁止上述显式对引用类型再施加引用,但如果在上下文环境中(包括模板实例化、typedef、auto类型推断等)如出现了对引用类型再施加引用,则施行引用塌缩规则(reference collapsing rule)[注 10]:
T& &变为T&
T& &&变为T&
T&& &变为T&
T&& &&变为T&&
我就说我将T换成具体的变量类型就不行了
所以, 当foo(T &&t) 被传入左值的时候, 比如 1, T 就变成了 int &, 所以foo(T &&t) 就变成了foo(int & &&), 根据上面的规则, 就变成了foo(int &)