Bootstrap@TLab

1 августа 2015

Мне как-то было нечем заняться на выходных, и на глаза попался старый сайт TLab. Я давно хотел что-нибудь там обновить, но не особо знал, что именно. Обновить, конечно, можно много чего, но начать я решил с сайта.

Обычно я не пользуюсь фреймворками, но захотел попробовать Twitter Bootstrap. Нашел подходящий шаблон, и занялся его переделыванием.

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

Поэтому вместо всяких слоганов я решил прикрутить карусель — получается, просто сделал то, что и так было раньше. Правда, лишние ссылки и подписи решено было убрать, да и сами слайды сделать просто картинками. Скринсейвер на Flash и полотно иконок, генерируемое на Javascript, конечно, забавно, но не нужно. К тому же, я не уверен, насколько хорошо это работало бы во время перехода между слайдами, и разбираться с этим не сильно хотелось.

Поскольку все эти одностраничные сайты у меня ассоциировались с плавной прокруткой между экранами, я решил все же добавить такую и себе. Поэтому на главной появился второй экран — с «описанием» TLab. Этим я заменил отдельную страницу, которую все равно вряд ли кто-то посещал.

Несмотря на то, что в шаблоне была плавная прокрутка к позиции на странице, она была добавлена только к клику по кнопке в панели навигации. Я же подумал, что точно где-то встречал подмену прокрутки колесом мыши на автоматическую прокрутку до следующего экрана в заданном направлении, поэтому написал её сам. В целом, вышло неплохо, хотя в начале прокрутки она немного дергается. Я решил, что и так сойдет — перехватывать событие мыши было нельзя, потому что поначалу у меня после последнего экрана на странице было дополнительное пространство, и я хотел сделать так, чтобы туда можно было скроллить по-обычному. Сейчас, когда на главной всего два полных экрана, можно было бы и перехватить событие мыши, но лень.

Поскольку подходящей крупной пикчи у меня не было, а старую ставить как-то не хотелось, вспомнилась мне другая штука. Это подстраивающийся под размер страницы canvas, на котором отрисовывается треугольная сеточка, а по самому центру — заготовленная картинка-треугольник. Я немного подредактировал код, и теперь вместо старой ограниченной в размерах jpg-картинки у меня был адаптивный canvas, градиент на котором подбирается по размеру страницы, а потому и выглядит неплохо. Он-то и используется в качестве фона на страницах сайта.

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

Прикручивать карусель ещё и на каждую страницу игры мне было лень, поэтому я оставил старую галерею.

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

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

Но меню — не единственное, что подстраивается под экран. Карусель на узких экранах я заменил на полноэкранные изображения, плавную поэкранную прокрутку на них выключил (хотя на телефонах все равно не приходит событие мыши, но это на всякий случай, чтобы не раздражало), а оставшиеся от старого сайта ограничения на 800 пикселей — выпилил. Теперь количество колонок меняется в зависимости от ширины, а на страницах игр основная информация вылезает наверх и растягивается, чтобы удобнее было читать. Обновил и галерею — теперь размер скриншота подстраивается под экран, и никогда не вызывает горизонтальную прокрутку.

Вместе со всяким барахлом пропали и несколько игр. Некоторые все ещё упомянуты в описаниях других, но совсем уж трешовые решил выкинуть.

Внешний вид сайта особо не изменялся с 2012 года — вот как он выглядел тогда:

Nuit du Hack 2k15

2 июля 2015

Вместо экзамена по физике на этой сессии я был в составе нашей университетской команды по CTF в Париже на финале Nuit du Hack. К слову, это мой первый в жизни перелет и ранее далее Новосибирска я никуда не выбирался. Пилот этого самолета оказался самым приветливым, и даже хотел устроить «экскурсию», показывая пассажирам города, над которыми мы пролетаем. Правда, ничего у него не вышло, потому что большинство пассажиров спали, но он по крайней мере старался. В Москве мы разве что взяли немного евро в банке, и полетели дальше.

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

Отель не был особо удивительным, разве что карта-ключ для комнаты показалась мне необычной. Комната была небольшой, но с мягкими кроватями-подушками. Расположившись, мы сходили в замеченный неподалеку McDonald’s, а потом отправились гулять по окрестностям. Найденный на карте замок был закрыт на реставрацию, а больше ничего особенного в округе и не было.

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

На следующий день мы отправились в центр, пофоткаться у достопримечательностей. На станции мы взяли универсальный билет во все пять зон на два дня. Как сказал нам местный француз, «It’s quite expensive» — 37 евро или около того. Зато по этому билету можно было ездить хоть на RER, хоть на метро, а не покупать билеты на станции каждый раз.

Когда мы фотографировали небольшой фонтанчик, к нам подоспели цыгане. Сначала я отказывался от подачи «глухонемым», но потом решил, что пять-то центов занести можно. Когда я достал кошелек, одна из цыганок вырвала тысячу рублей и удалилась в неизвестном направлении. Евро, кстати, не пытались вырывать. Проходящий мимо чернокожий парень пытался нам показать, что связываться с ними не надо, но было уже поздно.

Мы шли в сторону Лувра вдоль какой-то реки, а на тротуаре продавали различные сувениры — брелки, магниты, картины, страницы из комиксов, тарелки и все такое. Я, кстати, сбегал в один книжный магазин, но не заметил там комиксов.

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

Завершив свой небольшой тур по достопримечательностям, мы сели на RER и поехали туда, где должны были пройти соревнования. На этой станции турникеты были закрыты решёткой, а сбоку была открыта калитка. Район казался каким-то заброшенным, поскольку там было очень мало прохожих, а большинство магазинов и кафе были закрытыми. Мы попытались найти хоть какое-нибудь место, в котором можно было бы поесть, но они были либо какими-то непривлекательными, либо закрытыми. Поэтому мы дошли до McDonald’s, и снова поели в нем.

Потом мы добрались до места проведения соревнований. Оставалась ещё пара часов до начала, все футболки и другой стафф уже были раскуплены (разве что были наклейки). Мы походили по зонам, в которых проходили разные мероприятия в рамках евента, и сели дожидаться начала в каком-то клубе, где организаторы играли друг с другом в настольный футбол. Когда мы пошли в здание, выделенное для CTF, большинство команд уже расположились там. В общем-то, мы успели только подключить ноутбуки, когда организаторы выгнали всех — одна из команд получила доступ к заданиям и машинам других участников, в то время как некоторые другие команды не имели доступа к собственной сети. Игру отложили на час, а для нас сготовили барбекю. Через час, правда, ничего они не починили, поэтому вместо Attack/Defense (который они называли Private CTF) они просто дали всем доступ к проходившему здесь же Jeopardy (Public CTF).

Некоторые таски были очень простыми; удивило также наличие двух похожих тасков с использованием азбуки Морзе. Над одной из задач парень из нашей команды бился очень долго, а все дело было в переносе строки, который не подразумевался, но при этом-таки был нужен. В общем, среди девяти участвовавших команд, наша заняла шестое место.

Уставшие, мы вернулись в отель и поспали несколько часов перед вылетом. Когда ехали в аэропорт на RER’е, в наш вагон зашли музыканты и играли, пока мы не доехали. Перелёт в Москву был довольно удачным — мне не сильно хотелось спать, сидел у окна, было светло, покормили вкусно. Успел повторить теорию вероятностей. Во время перелёта в Новосибирск уже стал засыпать, и вернувшись в общагу утром, лег подремать, а проснулся уже вечером.

Тервер я подготовил не очень, физику сдавал на самой дальней пересдаче, 30 июня, но нормально разобраться тоже не смог. Сессию закрыл и вернулся в Новокузнецк вместе со своим стационарным компом. Теперь можно спокойно работать над своим Google Summer of Code проектом, а остаток времени провести за компьютерными играми.

Spider Player Addon

12 апреля 2015

В одном из обновлений своей утилиты я сделал так, что название трека добавляется к ссылке как параметр запроса, который игнорируется vk, чтобы в подсказке я мог всё-таки увидеть название.

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

Кроме того, я поискал Spider Player по Github, и нашёл один-единственный репозиторий, в котором был веб-интерфейс для плеера на Meteor. Я никогда не пользовался веб-интерфейсом Spider Player, потому что не знал, что он вообще у него есть. Оказывается, можно сделать так, чтобы плеер выдавал инфу о своём состоянии и реагировал на простые команды по http. Сначала я побаловался с Meteor-версией, но потом решил пойти дальше.

Я написал расширение для Firefox, которое следит за состоянием плеера и выдаёт стильную подсказку с именем исполнителя и названием трека при переключении.

Оно также добавляет кнопочку, которая открывает небольшое окошко с минималистической версией плеера (да, только кнопка Play/Pause, но я всё равно даже ею не пользуюсь).

Но самое главное — оно добавляет в контекстное меню браузера возможность быстро добавить треки в плейлист. Если нажать правой кнопкой по ссылке на пост vk или если нажать правую кнопку на странице самого поста, то в менюшке будет пункт «Добавить в Spider Player». При этом расширение создаёт временный txt-файл для моей утилиты и небольшой bat-скрипт, который делает всё необходимое. Потом она запускает этот скрипт, скрипт запускает утилиту на Java и передаёт сгенерированный плейлист плееру. Всё это работает пару секунд, и при этом не требует правки файла и запуска утилиты скриптиком вручную.

Единственный недостаток варианта с веб-интерфейсом, правда, заключается в том, что он отваливается примерно каждый час, и поэтому стильные подсказки прекращают появляться. Возможности перезапустить его автоматически, кажется, нет. Алсо, подсказочка привязана к браузеру, поэтому при переключении в другие приложения её не видно. Может быть я найду способ исправить и это.

P.S. Я ещё не придумал название, поэтому не выкладываю никуда. К тому же, кто вообще им будет пользоваться?

BackdoorCTF

2 апреля 2015

Мы тут участвовали в BackdoorCTF, и я решил написать небольшой врайтап по поводу таска, который решил.

Решил я, конечно, не один таск, но в основном это были простые таски типа получить 100 QR кодов и быстро их сосканить (т.к. по-быстрому найти что-нибудь подходящее для питона не удалось, взял консольную ZBar для винды и просто вызывал в нужный момент).

Но это не тот таск, о котором я собрался рассказывать. Самым интересным для меня таском оказался bbad. Нам даны 4 файла, один бесполезен, в другом лежит то, что надо расшифровать, и оставшиеся два нужны для того, чтобы понять, как это расшифровывать.

В одном файле у нас лог, а в другом — вывод каждой команды. Несложными регулярками я удаляю ненужную инфу и ручками собираю команду и её вывод рядом, чтобы анализировать было проще.

Сразу бросается в глаза то, что если вторым параметром идёт 1, то в выводе вторым идёт 0. Так как разделены они символом ’^’, я подумал, что это степень, и что шифруется так, чтобы выражение в указанной степени было равно второму параметру (по модулю, конечно).

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

Несложно также заметить множество простых чисел в выводе (для нас специально сделали подборку команд, в которых шифруется только один символ). В голову приходит, что символу соответствует какое-то число, и можно попробовать выяснить закономерность. Сгруппировав команды от ’1′, ’2′, ’3′, ’9′, ’0′, замечаешь, что числа подозрительно простые, и к тому же ’9′ соответствует девятое простое, а ’0′ - десятое.

Вскоре замечаешь, что ’q’ соответствует 11-ое простое число. И другим буквам тоже соответствуют простые, но закономерности не видишь. Смотришь на клавиатуру — а ’q’ идёт сразу после ’0′. Вооружившись первой сотней простых чисел и пробежавшись по клавиатуре, я с помощью регулярки генерирую тело функции, которая будет переводить символ в соответствующее число (кто-то не знает про dict в питоне, да).

Запускаем на всех односимвольных входах с ключом 1 — и выходное первое число всегда совпадает с соответствующим простым. Успех! Идём дальше. Время попробовать более длинный текст с ключом 1: ’abcd’. Вероятно, символы всё ещё кодируются простыми числами, но непонятно, складываются их коды, перемножаются и зависят ли они от позиции символа. Сначала пробуем просто перемножить их все, и получаем неверный ответ. Тогда пробуем возвести код символа в степень, соответствующую его позиции в тексте. Получается. Круто, мы решили таск для ключа, равного 1.

Теперь надо разобраться с тем, как зависит ответ от ключа. Тут нам пригодится группа команд, которые работают с текстом ’V’, но используют разные ключи. Для 1 наш ответ уже совпадает. Если присмотреться, то закрадывается мысль, что ответ примерно в <ключ> раз меньше простого числа, соответствующего нашему символу. Проверяем на калькуляторе — делим нацело — полностью совпадает.

Непонятно только, нужно ли делить на ключ код каждого символа или получающееся сообщение и сколько раз на него нужно делить. Пару раз попробовав, выясняю, что на ключ делят один раз. Это, конечно, неплохо, но что делать с числом, которое стоит после ’^’? Мы ещё не придумали, как вычислить его, если только это не случай с ключом, равным 1 (там просто ставим 0).

Я пробовал свою догадку с возведением в степень и взятием остатка от 12000 (число, встречающееся в условии), но она оказалась неверной. Довольно очевидная идея о том, что это остаток от деления, пришла ко мне не сразу, причём довольно случайно — я просто решил это проверить, хотя и не думал, что это окажется верным решением. В общем, так мы выяснили, как получить оба числа, печатаемых в ответ.

Осталось лишь декодировать зашифрованное сообщение. Правда, у нас нет ключа, который используется для кодирования. В условии написано, что он не может быть больше 12000. Кроме того, мы знаем, что второе число — остаток от деления на наш ключ. Так как остаток от деления больше ключа быть не может, а ключ на всё сообщение один, то минимальный ключ, которым можно было его зашифровать, должен быть больше любого из остатков, указанных в нашем зашифрованном тексте. Максимальный остаток — 8923, так что начинаем перебирать ключи с 8924, и заканчиваем 12000. Отметим также, что у нас в сообщении есть два небольших частных от ключа — 33 и 47. Вероятно, это короткие слова, которые будет несложно декодировать и по ним понять, подходящий ли ключ был найден.

Отметим, что код слова мы можем получить как a*key+b, где a, b — пара чисел, указанных в зашифрованном тексте. Кроме того, код слова — произведение простых чисел, соответствующих символам 0-9a-zA-Z, поэтому если при разложении кода мы получаем слишком большое простое число, можно сразу отбросить подобранный ключ. Более того, каждое число должно встречаться уникальное число раз, и это число раз должно находиться в диапазоне от 1 до количества уникальных простых чисел в разложении. (Сейчас, при написании этого поста, я понял, что если в слове один и тот же символ встречается дважды, то степень при соответствующем ему простом числе будет суммой номеров позиций, в которых находятся эти символы. Я просто отбрасывал подобные комбинации.) Таким образом, мы можем отбросить очень большое число различных неподходящих ключей.

Где-то третий найденный подходящий ключ выдал слово «is». Я остановил перебор и попробовал дешифровать всё сообщение этим ключом. Так я получил сообщение, в котором говорилось, что флаг — sha-256 от xY3wL1Sg. Его и сдаём.

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

Если что — мы восьмые.


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

Музыка

15 февраля 2015

Несколько дней назад видел на хабре статью о генерации потокового плейлиста из вк. Чувак написал небольшой сайтец, который предлагает ввести id пользователя или группы и количество записей, нажать на кнопку и получить возможность скачать сгенерированный плейлист.

Интересно то, что подобный плейлист можно открыть плеером, который поддерживает потоковое воспроизведение и слушать музыку из вк в нём, а не в браузере. Я попробовал запустить плейлист в Spider Player, которым пользовался оффлайн, пока не переехал вк и Яндекс.Музыку, и всё заработало. То есть можно не открывать вкладку в браузере и пользоваться его интерфейсом, а по-человечески переключать треки, включать и выключать перемешивание нажатиями горячих клавиш.

Я часто открываю записи с музыкой из своей ленты новостей в новых вкладках, чтобы послушать что-то новое или переслушать знакомые треки. Этих вкладок у меня очень много. Кроме открытых в браузере (и раскиданных по жанрам и другим критериям в разные группы вкладок) у меня есть ещё текстовый файл с тысячью ссылок. По всем этим ссылкам открываются различные посты из вк с прикреплённой музыкой, где-то по одному треку, где-то по девять-десять, с подборками по жанрам, группам или ещё чему-нибудь. Некоторые посты были удалены, некоторые аудиозаписи были удалены, множество записей в разных постах совпадают, а я уже и сам не помню, какие группы и треки я слушал, а какие нет.

К сожалению, тот сайт не предназначен для создания плейлистов из прикреплений в постах. Поэтому я решил написать собственную утилиту. Я начал было писать iframe-приложение на javascript, но вк хотел открыть мой сайт по https-ссылке, а у меня нет SSL-сертификата, и потому приложение просто не загружалось. Я написал ещё несколько версий на javascript и php, использующих различные методы работы с VK API, но несмотря на то, что они работали, им приходили неправильные ссылки. Как заметили в комментарии на хабре, вк может отдавать ссылки на vk-cdn.net или на vk.me. Моим скриптам сервер возвращал ссылки на vk-cdn.net. Они выдавали 404, когда я их открывал, и не работали в плеере. Я пробовал менять настройки приложения, получать другие права и бессрочный токен, но это не помогало.

Честно говоря, я так и не понял, как же на том сайте такие же методы VK API, вызываемые через PHP, получают ссылки, которые нормально работают для нужного пользователя, но в конце-концов я просто попробовал написать Desktop-приложение, и оно получило необходимые ссылки.

После этого я прикрутил возможность получать как треки из конкретной записи на стене, так и плейлист пользователя (с автоматическим вычислением количества записей), и сделал так, чтобы по ссылке приложение само определяло, какой запрос отправить. Получая набор ссылок, оно проделывает необходимые запросы и создаёт плейлист, который можно использовать в своём плеере.

Правда, он предпочитает отображать в качестве названия записи имя файла, а не прописанное в плейлисте название, поэтому при переключении на трек из вк отображается что-то такое:

Тем не менее, теперь можно использовать горячие клавиши в любимом плеере. А ещё можно анализировать сгенерированные плейлисты и удалять повторяющиеся треки или сортировать их по какому-либо принципу (например, все треки одной группы собирать вместе), вместо того, чтобы слушать небольшие подборки в одной из сотен вкладок.

1 2 3 4