Вычислить хэш SHA1 из двоичного кода и проверить с предоставленным хешем
Я подал заявку на работу, и они попросили меня написать код со следующими требованиями:
Получите описание «панели инструментов» из http..update.utorrent.com /installoffer.php? Предложение = трубопровод. Разберите bencoded (см. http://en.wikipedia.org/wiki/Bencode ) ответ и извлеките URL-адрес двоичного файла и его хэш SHA1. Хеш содержится в значении ключа «offer_hash». Бинарный файл находится в списке для key 'offer_urls' - пожалуйста, используйте один префикс с «Http..download.utorrent.com /".
Загрузите двоичный файл и вычислите его хэш
Убедитесь, что вычисленный SHA1-хэш идентичен тому, который указан в деталях предложения. Вполне возможно использовать существующие библиотеки для bencoding, хэширование и т. д.
Что не так с моим кодом? Рекрутер сказал, что не встретил их бар.
# Script that verifies the correctness of a toolbar offers
import urllib, bencode , hashlib
from hashlib import sha1
url = "http://update.utorrent.com/installoffer.php?offer=conduit"
filename = "content.txt"
f= urllib.urlretrieve(url, filename)
#Bdecoding the response
with open (str(filename), 'rb') as myfile:
data=myfile.read()
decoded = bencode.bdecode(data)
# Returning the list for the key 'offer_urls'
list = decoded['offer_urls']
#print list
# Returning the URL of the binary that is prefixed with "http://download3.utorrent.com/"
length = len (list)
prefix = "http://download3.utorrent.com/"
i= -1
while i < length:
i = i + 1
if list[i].startswith(prefix) :
break
binary= list[i]
print "The URL of the the binary is: " , binary
# Returning the sha1 hash contained in the value of the key 'offer_hash'
encrypted_hash = decoded['offer_hash']
sha1_hash1 = encrypted_hash.encode('hex')
print "The sha1 hash contained in the value of the key 'offer_hash' is: " , sha1_hash1
# Downloading the binary and calculating its hash
urllib.urlretrieve ( binary , "utct2-en-conduit-20130523.exe")
file = "C:\Python27\utct2-en-conduit-20130523.exe"
with open (file, 'rb') as myfile:
downloaded=myfile.read()
k = hashlib.sha1()
k.update(downloaded)
sha1file = k.hexdigest()
print "The sha1 hash of the downloaded binary is: " , sha1file
# Verify that the calculated sha1 hash is identical to the one provided in the offer details
if (sha1file == sha1_hash1) :
print "Test result = Pass"
else :
print "Test result = Fail"
4 ответа
Я собираюсь рассказать вам о вещах в вашем коде, что заставило меня задуматься.
# Script that verifies the correctness of a toolbar offers
import urllib, bencode , hashlib
Дополнительное пространство после bencode
предполагает отсутствие внимания к деталям.
from hashlib import sha1
url = "http://update.utorrent.com/installoffer.php?offer=conduit"
filename = "content.txt"
f= urllib.urlretrieve(url, filename)
Использование однобуквенных переменных предполагает отсутствие внимания к чистому коду.
#Bdecoding the response
with open (str(filename), 'rb') as myfile:
filename
уже является строкой. Преобразование его в строку снова вызывает путаницу в отношении того, что происходит.
data=myfile.read()
decoded = bencode.bdecode(data)
Массивный отступ предполагает отказ от согласованного стиля отступов.
Загрузка файла на диск, а затем чтение его в память - плохое использование доступных API. Вы должны загрузить файл непосредственно в память.
# Returning the list for the key 'offer_urls'
Избыточный пробел подсказывает, что кто-то входит в счастливый.
list = decoded['offer_urls']
«Возвращение» здесь технически неверно. У вас нет функции, поэтому вы ничего не возвращаете. Использование list
является плохим именем для переменной, поскольку это встроенный тип Python.
#print list
# Returning the URL of the binary that is prefixed with "http://download3.utorrent.com/"
length = len (list)
Помещение пробелов после вызовов функций нечетно, и вы не делаете это последовательно. Также редко есть веская причина для хранения длины списка list
.
prefix = "http://download3.utorrent.com/"
i= -1
Нет пробела перед =
.
while i < length:
i = i + 1
if list[i].startswith(prefix) :
break
binary= list[i]
Вы используете цикл while
, когда вы должны использовать цикл for
. Он также будет вызывать IndexError
, а не терпеть неудачу изящно, если префикс не найден.
print "The URL of the the binary is: " , binary
# Returning the sha1 hash contained in the value of the key 'offer_hash'
encrypted_hash = decoded['offer_hash']
Является ли этот хэш действительно зашифрованным?
sha1_hash1 = encrypted_hash.encode('hex')
print "The sha1 hash contained in the value of the key 'offer_hash' is: " , sha1_hash1
# Downloading the binary and calculating its hash
urllib.urlretrieve ( binary , "utct2-en-conduit-20130523.exe")
file = "C:\Python27\utct2-en-conduit-20130523.exe"
Жестко закодированное имя файла будет легко сломаться. Тебе даже не нужно это делать. Строка также содержит "\"
, который должен быть экранирован, или вся строка должна быть необработанной. то есть.
"C:\\Python27\\utct2-en-conduit-20130425.exe"
или
r"C:\Python27\utct2-en-conduit-20130425.exe"
или в большинстве случаев вы можете использовать другие косые черты даже в Windows.
"C:/Python27/utct2-en-conduit-20130425.exe"
Вы ушли с тем, что вы сделали, но это в основном потому, что вам повезло.
with open (file, 'rb') as myfile:
downloaded=myfile.read()
Этот последний фрагмент кода сделал почти то же самое, что и предыдущий бит кода, но вы не использовали функцию.
k = hashlib.sha1()
k.update(downloaded)
sha1file = k.hexdigest()
print "The sha1 hash of the downloaded binary is: " , sha1file
# Verify that the calculated sha1 hash is identical to the one provided in the offer details
if (sha1file == sha1_hash1) :
Вы поставили круглые скобки, которые не нужны.
print "Test result = Pass"
else :
print "Test result = Fail"
Основные проблемы:
- Ваш стиль плохой и непоследовательный
- Несколько вещей предполагают, что вы не совсем понимаете, что происходит.
- Вы не позаботились о том, чтобы прочитать код.
Вот моя проблема:
# Script that verifies the correctness of a toolbar offers
import urllib
import bencode
import hashlib
import contextlib
# it's common practice to put input details like this
# as global constants at the start of your script
URL = "http://update.utorrent.com/installoffer.php?offer=conduit"
PREFIX = "http://download3.utorrent.com/"
# by breaking down your task into functions
# you can make the code easier to follow
def read_bencoded_url(url):
with contextlib.closing(urllib.urlopen(url)) as offer_file:
return bencode.bdecode(offer_file.read())
def find_string_with_prefix(strings, prefix):
for string in strings:
if string.startswith(prefix):
return string
else:
raise Exception("Did not find prefix: {}".format(prefix))
# this function is a bit more complicated
# but it avoids saving the file to disk or loading it entirely into memory.
# instead it hashes it 4096 bytes at a time
def hash_of_url(url):
hasher = hashlib.sha1()
with contextlib.closing(urllib.urlopen(url)) as binary_file:
while True:
data = binary_file.read(4096)
if not data:
break
hasher.update(data)
return hasher.hexdigest()
# the actual high level logic just calls the functions
# this avoid obscuring the logic with lower level details
def main():
decoded = read_bencoded_url(URL)
binary = find_string_with_prefix(decoded['offer_urls'], PREFIX)
reported_hash = decoded['offer_hash'].encode('hex')
actual_hash = hash_of_url(binary)
print "The sha1 hash contained in the value of the key 'offer_hash' is: ", reported_hash
print "The sha1 hash of the downloaded binary is: " , actual_hash
if reported_hash == actual_hash:
print "Test result = Pass"
else:
print "Test result = Fail"
if __name__ == '__main__':
main()
Запустите свой код через pep8 и, возможно, более педантичный статический анализатор, например pylint .
Вы обнаружите, что эти инструменты не любят некоторые ваши имена форматирования и переменных. Они, скорее всего, будут жаловаться, что слишком много переменных, ветвей и т. Д., Потому что код не разбивается на модулированные функции.
Если бы я должен был взять ваш код, то умножайте его на 100 или тысячу раз в другие файлы (размер обычного коммерческого /корпоративного приложения, тогда он будет завтраком для собаки и не будет обслуживаться вообще.
Вам нужно больше заботиться о своем коде и сделать его понятным и последовательным. Подумайте об этом как о форматировании вашего резюме для потенциального работодателя. Используйте непротиворечивые пробелы между символами, непротиворечивые комментарии над кодом (а не несколько разрывов строк между ними) и, прежде всего, использовать один из общих руководств по стилю для языка. Уинстон опубликовал отличный пример раньше.
Это показывает, что вы, по крайней мере, можете написать код, который хорошо читает и представляет. Если вы кодируете в профессиональной среде, другие люди также должны прочитать код, который вы написали, и им нужно быстро это понять. Если они просматривают код, то внезапно на странице появляется случайный комментарий, который является настоящим отвлечением.
Хорошая книга для чтения - Чистый код Роберта Мартина . Вы должны прочитать это так, как если бы ваша жизнь зависела от него.
Проблемы:
-
Я бы сказал, что
import
должен быть эффективным способом повторного использования библиотек.import urllib, bencode , hashlib from hashlib import sha1
В приведенной выше строке кода вы импортировали
hashlib
иsha1
изhashlib
во вторую строку. В этом нет ничего плохого, но когда вы просто хотите использовать толькоsha1
, тогда нет необходимости импортировать весь класс.То же самое с другими классами: сколько членов вышеупомянутых библиотек вы использовали в своем коде?
-
Все константы должны быть предопределены в начале сценария, а не там, где это необходимо.
-
Что делать, если указанный файл не открывается (в случае отсутствия файла)? Как вы справляетесь с этим исключением?
with open (str(filename), 'rb') as myfile: downloaded=myfile.read()
Используйте try-except для исключения исключений.
-
Имя файла уже является строкой.
-
Не нужно использовать дополнительную переменную для хранения длины списка. Также есть промежуток между функцией
len
и ее аргументом.length = len (list)
-
Используйте цикл
for
для индексирования, что лучше, чем использование циклаwhile
. -
Бесконечные имена переменных, такие как
i
,f
,k
. -
Задачи не делятся на разные подпрограммы.