Вычислить хэш 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"
190 голосов | спросил user26614 27 J0000006Europe/Moscow 2013, 07:55:04

4 ответа


336

Я собираюсь рассказать вам о вещах в вашем коде, что заставило меня задуматься.

# 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"

Основные проблемы:

  1. Ваш стиль плохой и непоследовательный
  2. Несколько вещей предполагают, что вы не совсем понимаете, что происходит.
  3. Вы не позаботились о том, чтобы прочитать код.

Вот моя проблема:

# 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()
ответил Winston Ewert 27 J0000006Europe/Moscow 2013, 10:19:03
55

Запустите свой код через pep8 и, возможно, более педантичный статический анализатор, например pylint .

Вы обнаружите, что эти инструменты не любят некоторые ваши имена форматирования и переменных. Они, скорее всего, будут жаловаться, что слишком много переменных, ветвей и т. Д., Потому что код не разбивается на модулированные функции.

ответил Jace Browning 27 J0000006Europe/Moscow 2013, 07:57:00
40

Если бы я должен был взять ваш код, то умножайте его на 100 или тысячу раз в другие файлы (размер обычного коммерческого /корпоративного приложения, тогда он будет завтраком для собаки и не будет обслуживаться вообще.

Вам нужно больше заботиться о своем коде и сделать его понятным и последовательным. Подумайте об этом как о форматировании вашего резюме для потенциального работодателя. Используйте непротиворечивые пробелы между символами, непротиворечивые комментарии над кодом (а не несколько разрывов строк между ними) и, прежде всего, использовать один из общих руководств по стилю для языка. Уинстон опубликовал отличный пример раньше.

Это показывает, что вы, по крайней мере, можете написать код, который хорошо читает и представляет. Если вы кодируете в профессиональной среде, другие люди также должны прочитать код, который вы написали, и им нужно быстро это понять. Если они просматривают код, то внезапно на странице появляется случайный комментарий, который является настоящим отвлечением.

Хорошая книга для чтения - Чистый код Роберта Мартина . Вы должны прочитать это так, как если бы ваша жизнь зависела от него.

ответил user2503552 28 J0000006Europe/Moscow 2013, 03:59:40
26

Проблемы:

  1. Я бы сказал, что import должен быть эффективным способом повторного использования библиотек.

    import urllib, bencode , hashlib
    from hashlib import sha1
    

    В приведенной выше строке кода вы импортировали hashlib и sha1 из hashlib во вторую строку. В этом нет ничего плохого, но когда вы просто хотите использовать только sha1, тогда нет необходимости импортировать весь класс.

    То же самое с другими классами: сколько членов вышеупомянутых библиотек вы использовали в своем коде?

  2. Все константы должны быть предопределены в начале сценария, а не там, где это необходимо.

  3. Что делать, если указанный файл не открывается (в случае отсутствия файла)? Как вы справляетесь с этим исключением?

    with open (str(filename), 'rb') as myfile:
           downloaded=myfile.read()
    

    Используйте try-except для исключения исключений.

  4. Имя файла уже является строкой.

  5. Не нужно использовать дополнительную переменную для хранения длины списка. Также есть промежуток между функцией len и ее аргументом.

    length = len (list)
    
  6. Используйте цикл for для индексирования, что лучше, чем использование цикла while.

  7. Бесконечные имена переменных, такие как i, f, k.

  8. Задачи не делятся на разные подпрограммы.

ответил Abhishek Kulkarni 28 J0000006Europe/Moscow 2013, 14:06:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132