技術債務終於還得差不多了
阿新 • • 發佈:2019-01-05
這周把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嘛,就是要看不懂防止破解——額,無語。這個程式碼的問題是:
- 最開頭那個
{
後面,就是函式宣告那裡,竟然換了兩行,其他地方就只有一行,這種就是隨機的程式碼。 rsa_shield
為NULL時,就用password,也就是這個函式其實有可能用rsa,有可能用aes,反正這個用什麼是說不太清除的。end
標籤,這種c語言的GOTO,其實用結構體儲存指標,然後釋放會好些(模擬C++的解構函式)。- 變數宣告在最開頭,其實現在的C編譯器都支援在用的地方宣告變數。變數寫在一坨,擴大了作用域,都不知道幹啥。可能是因為goto導致的。
copy_mem_bio_data
,這種也算個函式?直接讀就好了,就幾行程式碼,不是看著幾行程式碼湊齊了就搞個函式,那初中生的水平就知道怎麼劃分函式。write_bio
這種變數命名,像是個函式,動詞加名詞。好神奇的名字。而且型別作為字尾,真的是太初級了,我想起了vhost_list
,app_array
,refer_vector
長篇累牘的鬼名字。error_log
每個日誌函式後面都加\n
,這種用巨集定義展開自動加不好麼?查查__VA_ARGS__
這個巨集定義就知道了。- 返回值是
char*
,要是有錯誤咋辦?返回NULL
?咋知道是啥錯誤?應該用錯誤碼的,輸出的buf用指標嘛。 - 整個函式的職責不清晰,裡面的程式碼混合了太多引數,各種資料流都不知道幹啥的。
總之,這種程式碼就是小學生的水平,或者是喝醉了的程式設計師寫的吧。反正時代久遠,也不知道誰寫的了。
看水平高點的猴寫的程式碼:
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深入淺出我每個例子都敲過程式碼理解過,資料結構我都實現過,人月敏捷我認真讀過,設計模式我都能畫出來),你基礎差我這麼多,積累也差我這麼多,有什麼理由不好好學習?
不好好學習不長進的程式猴就是不要臉。