Вот тут я написал пост, каким идиотизмом считаю маниакальное пристрастие некоторых бесполезных топ-менеджеров истерически требовать от работников прихода ровно к стольки-то, даже если рабочий процесс на время прихода никак не завязан.
В комментах, конечно же меня ткнули носом в то, что это в немытой России я чем-то недоволен, а вот в благословенной Европе вообще все пунктуальны как Биг-Бен, и никогда не опаздывают, а если бы кто и опоздал, то штраф был бы выписан ему автоматически.
Так как я не только лаптём щи хлебаю, иногда половник в руки попадает, и по ряду причин немного представляю реальное положение дел в этом плане на Западе, то у меня эти влажные прозападные фантазии вызвали только лёгкую улыбку.
Но хули улыбаться, когда у меня есть для вас история не про какую-нибудь занюханскую восточногерманскую конторку, а ажно про целый банк UBS, "крупнейший в мире швейцарский банк", центральный (помимо цюрихского) офис которого пафосно располагается прямо в центре Лондона в большом здании.
Давным-давно в этом банке от Люксофта по почасовой ставке работал программистом один мой хороший друг. И требовалось от него в момент прихода на работу на компе залогиниваться и тыкать кнопку "Я пришёл". А если он это сделал после 9.00, то писать специальный емэйл специальному человеку и объяснять причину.
И если ты работаешь в дальнем от административных служб крыле, то чтобы сходить туда поставить крестик в документах, или какие-нибудь канцтовары получить, то надо спуститься со своего этажа, выйти на улицу, пройти до другого входа, снова дождаться лифта (который в рабочее время перегружен), расписаться в бумажке у кадровиков, и топать обратно. В рабочее время это может занять и полчаса, и больше.
Поэтому там принято заходить в административное крыло сразу по приходу на работу, а потом уже топать на рабочее место.
И вот мой товарищ раз написал емэйл "я не опоздал, я ходил показать своё лицо в кадры", два написал, ему оттуда и отвечают "чувак ты задолбал опаздывать, давай приходи вовремя просто". А он смотрит вокруг, что в 9.00 половины народа нет, потому что регулярно все ходят в административное крыло по разным административным нуждам, и письма с объяснениями "я не опездыл не опоздал" никто не пишет. Чует, что врут ему, а доказать не может.
Ну, в общем, дальше слово ему. Букв много, поэтому если вам техническая часть не интересна, после слов "Техническая часть", вставленных мной, можете не читать и перейти сразу к абзацу после слова "Конец технической части" с выводами и моралью.
***************************
Идея давно витала в воздухе, но за нее надо было взяться. Последней каплей стало совпадение во времени и пространстве двух факторов. Впрочем, надо сначала рассказать предысторию.
Для нас, представителей дешевой оффшорной рабочей силы, в банке существует система учета рабочего времени. Придя на работу, сотрудник должен зайти на соответствующую веб-страничку под своим логином/паролем и нажать на кнопочку "я пришел". В конце рабочего дня еще раз нажать на нее же: "я ушел". Разница во времени между этими двумя моментами заносится в базу данных, и впоследствии на основании этих данных банку выставляется счет за каждого из нас.
О том, что это надо делать, мне сообщили на втором месяце моего пребывания в Лондоне, но это так, мелочи :-) И к письму прилагалась просьба информировать обо всех случаях когда я забыл нажать кнопку, дабы наверху могли это поправить.
Так вот. Первым фактором послужило то, что мне сделали замечание, что я слишком часто забываю нажать на кнопочку, и что, мол, я один такой. Вот в это я, извините, не поверю никогда в жизни - мне слишком хорошо известна роль человеческого фактора в автоматизированных системах. Я скорее поверю в то, что я единственный, кто сообщает о том, что забыл нажать, и не ленится написать письмо об этом. А вторым фактором был приезд в Лондон barateli (aka dimachertov), который искренне и всей душой ненавидит эту систему и считает, что она глупа и порочна.
За обедом мы обсудили сложившуюся ситуацию и решили, что так дальше нельзя и с этим надо что-то делать. Надо написать скрипт, который будет отмечаться за нас. И нам хорошо - меньше забот, и начальству хорошо - меньше ошибок в отчетности. Даже странно, что до сих пор никто этого не сделал - в конторе полно программистов. Неужели задача настолько сложна?
Техническая часть
Оказалось, что задача и правда не из простых, тем более, что много сил тратить на ее решение не хотелось. Поэтому, чтобы не разбираться с внутрибанковской системой авторизации, решили обманывать систему на самом верхнем уровне - на клиентской стороне. Т.е. написать код на JavaScript, который будет за временем следить и кнопочки тыкать. В итоге ближе к вечеру, когда настал момент отмечать уход с работы, мы уселись разрабатывать принцип работы.
Камнем преткновения на нашем пути оказалась политика безопасности веб-браузеров, принятая не кем-нибудь, а самим консорциумом W3C. Можно слепить веб-страничку с фреймами и загрузить в один из фреймов страницу с кнопкой, только из JS-кода нельзя получить доступ к объектной модели документа, загруженного из постороннего домена. Соответственно, кнопочку не то, что нажать - даже увидеть не получится, если только не удастся воткнуть JS-ный код на сервер, где крутится база данных учета времени.
Ломать сервер ну очень не хотелось - это уже не мелкое хулиганство, за это и влететь может. Да и шансы на успех мизерны - все-таки банк, уж что-что, а система безопасности тут наверняка качественная, нам не по зубам. А вот на локальной машине можно творить практически все, что угодно, лишь бы постороннее ПО не ставили. Поэтому решили поискать лазейку в системе защиты браузера.
"В лоб" пробиться не удалось. Как мы ни пытались исхитриться, интерпретатор JavaScript четко отлавливал, что код из чужого домена, и к страничке-жертве нас не подпускал. Идея сменить браузер тоже не помогла - они все послушно следуют требованиям W3C.
Моя затея попробовать, используя AJAX, своровать исходный код HTML-страницы с сервера и при помощи JS/DHTML воткнуть его в рабочую страницу также успеха не принесла. Система учета времени сама написана с использованием сложной фреймовой структуры, и собрать на клиентской стороне поддельную копию веб-страницы не удалось. Почему-то по отдельности фреймы просто не грузятся - видимо, создатели предусмотрели такой подход.
Отчаявшись решить проблему на чисто клиентском уровне, мы решили попытаться спуститься уровнем ниже и просто тупо посылать требуемое событие непосредственно на сервер, имитируя нажатие. Оказалось, что и тут не все просто. Помимо пресловутой авторизации, выяснилось, что вместе с данными форма посылает еще какой-то безумной длины хэш, непонятно по какому принципу сгенерированный. Когда и по какому принципу он меняется - тоже неизвестно. Выковырять его из формы, конечно, можно, но... очень уж получалась сложная и ненадежная система, к тому же неизвестно, какие еще подводные камни нам встретятся при реализации.
В общем, мы немножко приуныли. Не хотелось верить, что мы не сможем заставить компьютер отмечаться за нас, но задача казалась неподъемной. И тут barateli практически случайно наткнулся на забавную особенность Internet Explorer'а: если написать в адресной строке javascript:(произвольный JavaScrit-код), то этот код исполнится. Сам по себе этот факт, в общем, не новость, хотя я и забыл про него напрочь, но самое главное: оказалось, что код исполняется в контексте загруженного в данный момент окна! И, соответственно, если в браузер была загружена система учета времени, из этого кода ее можно потрошить, как угодно!
Ухватившись за идею, я начал развивать ее. Основной проблемой было то, что при нажатии на кнопку окно перегружается и скрипт, как его часть, прекращает существование. Это было решено посредством открытия нового окна, в котором, собственно, и крутилась "жертва", а в первом окне работал скрипт, управляющий вторым окном. Во-вторых, писать весь скрипт в одну строчку - вещь крайне неудобная, поэтому, поразмыслив немного, я изобрел маленький скрипт, втыкающий в код страницы буквально следующее: <script src="https://myx.ostankin.net/test.js"></script>, где test.js, собственно, и содержит весь "зловредный" код. И это сработало! Недаром в CQG моими любимыми багами были HTML-injections! :-)
Вот, собственно, и все. Дальнейшее - дело техники.
Конец технической части
А мораль тут, кстати, довольно неожиданная. Мы с barateli на собственной шкуре ощутили эффективность "парного программирования" - методики из арсенала Extreme Programming. Никто из нас по отдельности не решил бы эту задачу: я без него уперся бы в какой-то один безнадежный подход, а он без меня не довел бы до логического завершения ни одну из своих идей. А в паре мы идеально дополняли друг друга: он беспрестанно генерировал идеи, а я либо сходу отфильтровывал совсем уж безумные, либо цеплялся за них и реализовывал. Он, в свою очередь, не давал мне закопаться в ненужные детали, не имеющие на данный момент практического значения.
Вот так мы и провели этот вечер: сидя за одним компом, с горящими глазами обсуждая возможность или невозможность того или иного подхода (порой чуть ли не на спор!), и в четыре руки переписывая код снова и снова, придавая ему все более и более причудливые формы. И в итоге родился подход, который пробил-таки брешь в системе защиты. Конечно, от прототипа, демонстрирующего техническую возможность нажать на кнопку из JS-скрипта, до работающей программы еще предстояло потрудиться, но главное было сделано.
В этот день я впервые за долгое время возвращался с работы довольный. А спустя еще пару вечеров я написал первую тестовую версию программы, которая отметила мой приход на работу ровно в 9:00, несмотря на то, что на самом деле я с утра был на встрече, проходившей в другом здании, и к компьютеру пришел только в без четверти 10.
P.S. Сегодня пришло в голову, что если, следуя маджентовской традиции, придумывать для проекта имя из греческой мифологии, то лучше, чем Prometheus, не найти :-) И не надо сарказма, я прекрасно помню, чем кончил Прометей!
Оригинал статьи тут: https://myx.ostankin.net/blog-archive/268
Блог живой, там можно комментировать, автор наверняка прочитает и ответит.