技术债务终于还得差不多了

这周把License授权给改了,由8个文件变成了3个,由2个工具变成1个,1515行觥筹交错的代码变成了1175行秩序井然的代码,维护难度由没有维护的无穷大变成很容易看得懂,支持的license长度由117字节变成无限,支持的授权方式由文件变成文件和网络。

这标志着我们技术债务还得差不多了,很快都是容易维护的社会主义产物了。无债一身轻啊!无债一身轻啊!无债一身轻啊!重要的事情说三遍,重要的事情说三遍,重要的事情说三遍。

贴一段非关键代码对比下,RSA加密然后用BASE64加密,之前的代码估计是被车轮战碾压过了,每个人都改一次,改得都不知道要干啥了:


}


char* aes_encipher(const char *in_buf, 
                   const char* password, 
                   RSA* rsa_shield,
                   int random_salt)
{
    char* out_buf = NULL;
    int rsa_in_len = 0;
    char* rsa_in_buf = NULL;
    int rsa_out_len = 0;
    char* rsa_out_buf = NULL;
    char salt[PKCS5_SALT_LEN] = {0};
    int in_buf_len = strlen(in_buf);

    BIO* write_bio = NULL;
    BIO* cipher_bio = NULL;

    BIO *b64_bio = BIO_new(BIO_f_base64());
    BIO *mem_bio = BIO_new(BIO_s_mem());
    if (!mem_bio) {
        error_log("BIO_new(BIO_s_mem()) error\n");
        goto end;
    }

    if (!b64_bio) {
        error_log("BIO_f_base64 can't be created\n");
        goto end;
    }
    write_bio = BIO_push(b64_bio, mem_bio);

    if (random_salt) {
        if (RAND_pseudo_bytes((unsigned char*)salt, sizeof(salt)) < 0) {
            error_log("PRNG error\n");
            goto end;
        }
    } else {
        strncpy(salt, magic, sizeof(salt));
    }

    if (!rsa_shield) {
        if (!(BIO_write(write_bio, magic, magic_len) == magic_len 
              && BIO_write(write_bio, (char *)salt, sizeof(salt)) == sizeof(salt))) {
            error_log("error writing salt to output\n");
            goto end;
        }
    } else {
        //include the '\0' end of password
        rsa_in_len = magic_len + PKCS5_SALT_LEN + strlen(password) + 1;
        rsa_in_buf = (char*)OPENSSL_malloc(rsa_in_len);

        memcpy(rsa_in_buf, magic, magic_len);
        memcpy(rsa_in_buf + magic_len, salt, PKCS5_SALT_LEN);
        strcpy(rsa_in_buf + magic_len + PKCS5_SALT_LEN, password);

        if (rsa_encrypt_or_decrypt(rsa_shield, rsa_in_buf, rsa_in_len, 
                                   &rsa_out_buf, &rsa_out_len, ENCRYPT) != 0) {
            error_log("rsa encrypt aes key error\n");
            goto end;
        }
        if (!(BIO_write(write_bio, rsa_out_buf, rsa_out_len) == rsa_out_len)) {
            error_log("write encrypted aes key error\n");
            goto end;
        }
    }

    cipher_bio = get_aes_cipher_bio(salt, password, ENCRYPT);
    if (cipher_bio == NULL) {
        error_log("get cipher bio error\n");
        goto end;
    }

    /* chain wbio and cipher_bio filter BIO */
    write_bio = BIO_push(cipher_bio, write_bio);

    if (BIO_write(write_bio, in_buf, in_buf_len) != in_buf_len) {
        error_log("error writing content to output\n");
        goto end;
    }

    if (BIO_flush(write_bio) != 1) {
        error_log("error flush to output\n");
        goto end;
    }

    out_buf = copy_mem_bio_data(mem_bio);

end:
    BIO_free_all(write_bio);

    if (rsa_in_len) {
        OPENSSL_free(rsa_in_buf);
    }
    if (rsa_out_buf) {
        OPENSSL_free(rsa_out_buf);
    }

    return out_buf;
}

谁要是能看懂就真的要跪地上给磕头,当然license嘛,就是要看不懂防止破解——额,无语。这个代码的问题是:

  1. 最开头那个{后面,就是函数声明那里,竟然换了两行,其他地方就只有一行,这种就是随机的代码。
  2. rsa_shield为NULL时,就用password,也就是这个函数其实有可能用rsa,有可能用aes,反正这个用什么是说不太清除的。
  3. end标签,这种c语言的GOTO,其实用结构体保存指针,然后释放会好些(模拟C++的析构函数)。
  4. 变量声明在最开头,其实现在的C编译器都支持在用的地方声明变量。变量写在一坨,扩大了作用域,都不知道干啥。可能是因为goto导致的。
  5. copy_mem_bio_data,这种也算个函数?直接读就好了,就几行代码,不是看着几行代码凑齐了就搞个函数,那初中生的水平就知道怎么划分函数。
  6. write_bio这种变量命名,像是个函数,动词加名词。好神奇的名字。而且类型作为后缀,真的是太初级了,我想起了vhost_listapp_arrayrefer_vector长篇累牍的鬼名字。
  7. error_log每个日志函数后面都加\n,这种用宏定义展开自动加不好么?查查__VA_ARGS__这个宏定义就知道了。
  8. 返回值是char*,要是有错误咋办?返回NULL?咋知道是啥错误?应该用错误码的,输出的buf用指针嘛。
  9. 整个函数的职责不清晰,里面的代码混合了太多参数,各种数据流都不知道干啥的。

总之,这种代码就是小学生的水平,或者是喝醉了的程序员写的吧。反正时代久远,也不知道谁写的了。

看水平高点的猴写的代码:

int SrsRsa::encrypt_hwinfo(string hwinfo, string& ehwinfo)
{
    int ret = ERROR_SUCCESS;

    if (bio) {
        BIO_free_all(bio);
    }

    BIO* mem_bio = BIO_new(BIO_s_mem());
    if (!mem_bio) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_new memory io failed. ret=%d", ret);
        return ret;
    }
    bio = mem_bio;

    BIO* b64_bio = BIO_new(BIO_f_base64());
    if (!b64_bio) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_new base64 io failed. ret=%d", ret);
        return ret;
    }
    bio = BIO_push(b64_bio, bio);

    // encrypted by segment RSA.
    string encrypted;
    if ((ret = srs_segment_rsa_encrypt(rsa, hwinfo, encrypted, false)) != ERROR_SUCCESS) {
        return ret;
    }

    // write to bio.
    if (BIO_write(bio, encrypted.data(), encrypted.length()) != encrypted.length()) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_write failed. ret=%d", ret);
        return ret;
    }

    if (BIO_flush(bio) != 1) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_flush failed. ret=%d", ret);
        return ret;
    }

    BUF_MEM* raw;
    BIO_get_mem_ptr(bio, &raw);
    ehwinfo.append(raw->data, raw->length);

    return ret;
}

卧草,不言自明吧?将硬件信息用RSA加密后用BASE64加密,就这么简单。维护这种清楚的代码,就是一种休闲,和游山玩水一样自在。一看到垃圾代码,就像吃垃圾一样,恶心头痛,腿抽筋。

各位看这个文章的程序猴们,能不能认真写好代码?提升水平,多看看经典的书,多学习,多改变?能不能不要一副年纪太大什么都懂,一听意见就狡辩?本人30岁了还学了go和scala,是在已经做完SRS之后(还没有骄傲自满),大学我就把经典的软件书籍都好好读了(MFC深入浅出我每个例子都敲过代码理解过,数据结构我都实现过,人月敏捷我认真读过,设计模式我都能画出来),你基础差我这么多,积累也差我这么多,有什么理由不好好学习?

不好好学习不长进的程序猴就是不要脸。

你可能感兴趣的:(技术债务终于还得差不多了)