...

суббота, 10 января 2015 г.

[Перевод] Padding Oracle Attack или почему криптография пугает

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

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


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

Частично я веду к тому, что вам никогда не следует расслабляться, всегда нужно быть начеку, изыскивая пути, которые злоумышленник может использовать для получения дополнительной информации о вашей системе, а частично к тому, что Padding Oracle Attack является крутой демонстрацией всего этого. Итак, начнем.





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

Так что, если мы шифруем предложение:


This is a sentence of a carefully chosen length.





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

В CBC каждый блок открытого текста складывается побитово по модулю два (xor) с предыдущим блоком шифротекста перед тем как поступить на вход алгоритму шифрования. Данная взаимозависимость блоков означает, что каждый блок шифротекста зависит от каждого блока открытого текста, который был обработан к данному моменту. Причем изменение любого байта открытого текста приведет к изменению всех последующих байт шифротекста (лавинный эффект, ага). Согласно Википедии — CBC является «одним из двух режимов симметричного блочного шифрования, рекомендованных Нилом Фергюсоном и Брюсом Шнайером».



Предпочтительным методом дополнения блоков шифротекста, является PKCS7. В нем значение каждого дополняемого байта устанавливается равным количеству дополняемых байт. Так если мы имеем блок из 12 символов, он будет дополнен четырьмя байтами [04, 04, 04, 04] до стандартного размера блока в 16 байт. Если блок имеет размер в 15 байт, он будет дополнен одним байтом [01]. Если блок имеет размер ровно в 16 байт, мы добавляем новый блок состоящий из [16]*16. (подробнее — http://ift.tt/1x8Oa3r)

Солгасно данному методу, последний блок расшифрованного открытого текста не может заканчиваться, например, на [..., 13, 06, 05]. А значит, что и оригинальный шифротекст является неверным, потому как не существует допустимых открытых текстов, которые могли бы быть преобразованы в такой шифротекст.




Оказывается, что знания факта, получается ли при расшифровке шифротекста открытый текст с корректным дополнением, достаточно атакующему для проведения успешной атаки на шифрование в режиме CBC. Если мы можем подавать какому-то сервису шифротексты, а он будет возвращать нам информацию, корректно ли дополнение — мы сможем вскрыть ЛЮБОЙ шифротекст.

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

Это не маловероятная ситуация. Например, Ruby OpenSSL подвержен данной проблеме. Достаточно использовать пример кода из официальной документации (http://ift.tt/17u54Vj):



decipher = OpenSSL::Cipher::AES.new(128, :CBC)
decipher.decrypt
decipher.key = "the most secret!"
decipher.iv = "also very secret"

plain = decipher.update("thewrongpadding!") + decipher.final




Данный код выдает OpenSSL::Cipher::CipherError: bad decrypt, который, если его не перехватить, вернет ответ с ошибкой 500.

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




Повторим еще раз — в CBC режиме каждый блок открытого текста побитово складывается по модулю два (XOR) с предыдущим блоком шифротекста перед тем как пойти на вход шифру. При дешифровании каждый шифротекст проходит через дешифратор и затем XOR'ится с предыдущим блоком шифротекста, чтобы произвести открытый текст.




Атака работает через вычисление «промежуточного состояния» процедуры дешифрования (смотри схему) для каждого блока шифротекста. Это состояние блока шифротекста после дешифрования блочным алгоритмом, но ДО процедуры XOR с предыдущим блоком шифротекста. Мы будем находить это состояние, поднимаясь снизу от открытого текста, вместо того, чтобы спускаться вниз через блочный шифр. Также мы вообще не будем волноваться на счет ключа шифрования или алгоритма блочного шифрования.

Почему же данное промежуточное состояние так важно? Заметим:



I2 = C1 ^ P2
и
P2 = C1 ^ I2




Мы уже знаем C1 т.к. это часть шифротекста, который мы имеем. Так что если мы найдем I2, мы можем легко найти P2 и расшифровать сообщение.



Вспомним, что мы можем подавать на вход системе любой шифротекст, и сервер ответит нам корректное ли дополнение получается после дешифрования. Мы используем данный факт, подавая на вход C1' + C2, где C1' — специальным образом сформированный нами блок шифротекста, а C2 — это блок, который мы хотим расшифровать. Под обозначением C1' + C2 мы понимаем простую конкатенацию (то-есть, «склеивание» блоков). Обозначим результат дешифрования как P'2.

Начнем с того, что мы заполним C1'[1..15] случайными байтами, а C1'[16] заполним нулем (0x00). Теперь подадим C1' + C2 серверу. Если сервер ответит, что дополнение получилось корректное, то мы можем быть уверены (с большой вероятностью), что P2'[16] равно 0x01 (т.к. дополнение корректно). Если сервер отвечает ошибкой — посылаем сообщение с C1'[16], установленным в 0x01, затем в 0x02 и.т.д. пока не получим нужный нам ответ.



(примечание переводчика. Конечно же возможна ситуация, когда мы получим два верных ответа:

1) для дополнения 01

2) для дополнения 02,02 или 03,03,03…


Если произошла такая ситуация — просто меняем предпоследний байт C1' и повторяем операцию заново.

В самом крайнем случае, нам понадобится три попытки, но это маловероятно.

)








Теперь положим, что сервер вернул ответ 200 при C1'[16] = 94.

I2 = C1' ^ P2'
I2[16] = C1'[16] ^ P2'[16]
= 94 ^ 01
= 95




Ура! Мы получили финальный байт промежуточного состояния. Т.к. C2 взят из реального шифротекста, то I2 тоже идентичен реальному. Поэтому, мы можем расшифровать последний байт настоящего открытого текста:

P2[16] = C1[16] ^ I2[16]
= C1[16] ^ 95




Мы подаем на вход C1'[16] = C1[16] и получаем последний байт реального открытого текста. На этом этапе, мы нашли всего-лишь заполнитель, так что придется проделать еще несколько итераций данного процесса, пока мы не обнаружим что-нибудь интересное.

Мы нашли последний байт прокручиванием C1' до получения корректного дополнения. При этом мы можем сделать заключение, что последний байт P'2 равен 0x01. Затем используя P2'[16] и C1'[16], находим I2[16]. Продолжая этот процесс, находим оставшиеся байты I2 и расшифровываем весь блок шифротекста.

Заполняем C1'[1..14] случайными байтами, C1'[15] устанавливаем в 0x00, а C1'[16] таким, чтобы получить P2'[16] == 0x02:



C'1[16] = P'2[16] ^ I2[16]
= 02 ^ 95
= 93




Теперь мы можем быть уверены, что P2' будет заканчиваться на 0x02, и поэтому единственный вариант, при котором P2' будет иметь корректное дополнение — если P2[16] == 0x02. Мы будем прокручивать C1'[15], пока сервер не выдаст нам код 200. Предположим, что это случилось при C1'[15] == 106. Проделываем опять то, что мы уже умеем:

I2 = C1' ^ P2'
I2[15] = C1'[15] ^ P2'[15]
= 106 ^ 02
= 104




И вуаля! Мы знаем предпоследний байт I2. Поэтому можем найти предпоследний байт P2, как мы это уже проделывали ранее:

P2[15] = C1[15] ^ I2[15]
= C1[15] ^ 104




И так далее для всех 16 байтов C2.

Форма блоков шифротекста зависит только от них самих и предшествующих блоков. Так что мы можем применить вышеприведенный алгоритм к каждому блоку шифротекста (отдельно от первого). Первый блок будет зашифрован с использованием вектора инициализации (IV), а сам IV выбран случайно при процедуре зашифрования. До тех пор, пока мы не узнаем IV, мы не сможем расшифровать первый блок, и нет ничего, что тут можно придумать, кроме глупого перебора очевидных значений [0,0,0,...] для IV и просмотра, получается ли какой-нибудь разумный открытый текст. И делать так в надежде, что первые 16 байт будут чем-нибудь вроде "Дорогой Евгений!".

Это все и есть Padding Oracle Attack.


Вот почему все, что связано с криптографией пугает.


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


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


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


Спасибо.


The Matasano Crypto Challenges (http://ift.tt/17u52Nf), благодаря которым я заинтересовался криптографией. Очень рекомендую!


_____


Перевод сделан с разрешения автора статьи Robert Heaton.

Источник: http://ift.tt/WVmsNr

Еще интересные ссылки по теме:

http://ift.tt/1x8ObEA


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Перевод] Краудфандинговая кампания OpenMandriva на IndieGoGo

Один из контрибьюторов OpenMandriva попросил меня разместить на Хабре перевод описания их краудфандинговой кампании. Я с готовностью согласился, т.к. очень уважаю opensource-сообщество (в работе использую Ruby on Rails, опенсорс — наше всё).

Некоммерческая ассоциация OpenMandriva происходит из старого сообщества Mandrake-Mandriva и является полностью независимой организацией, которая разрабатывает и поддерживает собственный линукс дистрибутив. Мы занимаемся разработкой ОС 2 года. Все участники проекта — добровольцы, которые верят в мир свободного ПО и бесплатно посвящают свое время разработке, дизайну, инфраструктуре проекта, целью которого является софт, свободный от любых шпионских программ. Юридически наша ассоциация зарегистрирована во Франции, но участники сообщества живут по всему миру, представляя более 30 стран со всех континентов.


Мы верим, что операционная система должна быть бесплатной для пользователя, быть адаптируемой к его нуждам, продвинутой технически, но в то же время легкой и удобной. У нас уже есть опыт разработки и поддержки ОС, которую вы можете уставить и попробовать прямо сейчас. Загрузить OpenMandriva Lx 2014.1 можно здесь: http://ift.tt/RvpRh3.




Если ОС уже существует, почему мы проводим кампанию? Наш следующий релиз запланирован на май 2015 года и нам нужна ваша помощь, чтобы и далее поддерживать и развивать этот высококачественный продукт.

То, что последние 2 релиза были загружены десятки тысяч раз, а отзывы хороши, воодушевило нас развивать проект. Убедитесь сами!



“Операционная система (OpenMandriva Lx 2014.1) стабильна, интерфейс дружелюбный. По большей части дистрибутив мне понравился. В OpenMandriva есть ощущение завершенности и дружелюбия, которые трудно квалифицировать, но которые точно есть. Установка системы, Центр Управления и приятное (уже традиционно) окружение рабочего стола, все спроектировано чтобы даже новичку было удобно. Особое впечатление произвело `systemd` пользовательское окружение. <...> OpenMandriva проделала отличную работу по полировке деталей systemd который отвечает за пользовательское окружение. <..> Из тех что я видел, OpenMandriva 2014.1 является одним из достойнейших короны «beginner friendly». Этот дистрибутив легок в установке, использовании, имеет отличный центр управления и должен подойти как для новичков так и для продвинутых пользователей. Я был доволен и впечатлен OpenMandriva 2014.1, рекомендую опробовать его.

Jesse Smith, Distrowatch






OpenMandriva Lx 2014.0 выглядит солидно и завершенно. Уровень качества на уровне, который может быть достигнут, только когда опытные разработчики и другие участники комьюнити всерьез вовлечены в проект. Большинство аппаратных устройств поддерживается и настроено по умолчанию. Однозначно очень хороший старт для следующих релизов. Поздравления команде OpenMandriva с этим релизом!

Gaël Duval, основатель Mandrake.






(OpenMandriva Lx 2014.0 Beta) глоток свежего воздуха с душой KDE.

Silviu Stahie, Softpedia.



Что нам нужно и что вы получаете?




Вся работа, необходимая для выпуска следующего релиза, делается добровольцами, международной командой участников сообщества. Деньги нам нужны для поддержки инфраструктуры (в основном хостинг серверов), эпизодической покупки необходимого железа (например, ARM boards) и демонстрации результатов работы на основных выставках open source (например FOSDEM, LinuxTag). Присутствие на выставках также важно для обмена информацией и изучения инноваций, для последующего внедрения их в нашу ОС. Общая сумма, необходимая на все эти нужды на 2015 год составляет $27, 500 USD.

Мы ставим целью кампании $15, 000 USD и надеемся, что с вашей помощью мы сможет собрать $27, 500 USD!

Мы верим, что тысячи наших пользователей и те, кто еще только станет ими, или те, кто просто верит и поддерживает качественные open source продукты сделают достижение цели возможным.

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

Что получаете вы?

Интуитивная и легкая в использовании, и в то же время продвинутая система, ориентированная на пользователя. Мы прислушиваемся к сообществу, проводим регулярные опросы пользователей и ведем разработку продукта максимально приближенно к пожеланиям. Система бесплатна и открыта. Мы приветствуем новых участников, которые хотят учиться новому в open source, вместе с профессионалами и в дружелюбной атмосфере. Наша задача — поддерживать и развивать свободное ПО, сохранять доступность продвинутого и удобного в использовании продукта для всех и каждого.

Мы делаем все, чтобы быть в авангарде новинок в мире OpenSource, и предоставлять нашим пользователям самое свежее и интересное. Пример этого можно увидеть в нашем релизе: мы переключились на LLVM/clang компилятор по умолчания одними из первых (http://ift.tt/1Ez66IY). Наслаждайтесь свежими интересными решениями вместе с нами!


Риски

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


Как еще можно помочь

Если вы не можете внести пожертвование, но хотели бы помочь, вы все равно можете это сделать!



  • распространите информацию о нашей компании везде где только можно — в вашем блоге, твиттере, расскажите вашим друзьям, расшарьте ссылку всюду где только можно — это поможет!

  • используйте инструменты Indiegogo по расшариванию!

  • присоединяйтесь к нашему проекту! Разработчики, переводчики, дизайнеры, специалисты по инфраструктуре или пиару, продвинутые или еще только учащиеся — мы растем и будем рады новым членам команды! Просто напишите несколько слов о вас на join@openmandriva.org!


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


QQuickRenderControl, или как подружить QML с чужим OpenGL контекстом. Часть I

Недавний релиз Qt 5.4, помимо прочего, предоставил в распоряжение разработчиков один, на мой взгляд, очень любопытный инструмент. А именно, разработчики Qt сделали QQuickRenderControl частью публичного API. Занятность данного класса заключается в том, что теперь появилась возможность использовать Qml в связке с любым другим фреймворком, если он предоставляет возможность получить (или задать) указатель на используемый OpenGL контекст.

С другой стороны, в процессе работы над одним из своих проектов, я столкнулся с необходимостью отрисовывать QML сцену на CALayer (Mac OS X), без малейшей возможности получить доступ к родительскому окну. Недельный поиск возможных вариантов решения проблемы показал, что самым адекватным решением будет как раз использование QQuickRenderControl из Qt 5.4, благодаря удачному совпадению, получившего статус релиза одновременно с возникновением вышеупомянутой задачи.

Изначально я предположил что задача плевая, и будет решена в течении пары вечеров, но как же я сильно заблуждался — задача заняла порядка полумесяца на исследования, и еще пол месяца на реализацию (которая все еще далека от идеала).



Несколько тезисов





  • QQuickRenderControl это всего навсего дополнительный интерфейс к реализации QQuickWindow для получения нотификаций об изменении QML сцены, а так же передачи команд в обратном направлении (т.е. фактически «костыль»);

  • Результат рендеринга будет получен в виде QOpenGLFramebufferObject (далее FBO), который в дальнейшем может быть использован в качестве текстуры;

  • Работать придется непосредственно с QuickWindow, соответственно сервис по загрузке QML предоставляемый QQuickView будет недоступен, и придется его реализовывать самостоятельно;

  • Поскольку никакого окна на самом деле не создается, возникает необходимость искуственно передавать события мыши и клавиатуры в QQuickWindow. Так же необходимо вручную управлять размером окна;

  • Пример использования QQuickRenderControl я сумел найти только один, в Qt 5.4 (Examples\Qt-5.4\quick\rendercontrol) — собственно по нему и проходили все разбирательства;


Что же нужно сделать для решения исходной задачи?




1) Реализовать настройку QQuickWindow для рендеринга в FBO и управления этим процессом через QQuickRenderControl;

2) Реализовать загрузку Qml и присоединение результата к QQuickWindow;

3) Реализовать передачу событий мыши и клавиатуры;

4) Отрисовать FBO (ради чего все и затевалось);

В данной статье я позволю себе остановится только на пункте 1), остальные пункты в последющих частях (если вы сочтете это интересным).


Настраиваем QQuickWindow




Внешний QOpenGLContext



Отправной точкой является OpenGL контекст в котором в конечном итоге и будет отрисовываться FBO. Но поскольку, с большой долей вероятности, работать необходимо с контекстом изначально не имеющим никакого отношения к Qt, то необходимо провести конвертацию контекста из формата операционной системы в экземпляр QOpenGLContext. Для этого необходимо использовать метод QOpenGLContext::​setNativeHandle.

Пример использования на основе NSOpenGLContext:

NSOpenGLContext* nativeContext = [super openGLContextForPixelFormat: pixelFormat];

QOpenGLContext* extContext = new QOpenGLContext;
extContext->setNativeHandle( QVariant::fromValue( QCocoaNativeContext( nativeContext ) ) );
extContext->create();




Список доступных Native Context лучше смотреть непосредственно в заголовочных файлах Qt ( include\QtPlatformHeaders ), т.к. документация в этой части сильно не полна.

Далее можно использовать этот контекст (но при этом необходимо внимательно следить чтоб изменения состояния этого контекста не входили в конфликт с манипуляциями владельца), а можно сделать shared контекст:



QSurfaceFormat format;
format.setDepthBufferSize( 16 );
format.setStencilBufferSize( 8 );

context = new QOpenGLContext;
context->setFormat( format );
context->setShareContext( extContext );
context->create();


Важным ньюансом для использования OpenGL контекста с QML является наличие в нем настроенных Depth Buffer и Stencil Buffer, поэтому если у вас нет возможности влиять на параметры исходного контекста, нужно использовать shared контекст с установленными «Depth Buffer Size» и «Stencil Buffer Size».


Создание QQuickWindow



При создании QQuickWindow предварительно создается QQuickRenderControl и передается в конструктор:

QQuickRenderControl* renderControl = new QQuickRenderControl();
QQuickWindow* quickWindow = new QQuickWindow( renderControl );
quickWindow->setGeometry( 0, 0, 640, 480 );




Кроме того важно задать размер окна, для дальнейшего успешного создания FBO.
Инициализация QQuickRenderControl и QOpenGLFramebufferObject



Перед вызовом QQuickRenderControl::initialize важно сделать контекст текущим, т.к. в процессе вызова будет сгенерирован сигнал sceneGraphInitialized, а это хорошая точка для создания FBO (который, в свою очередь, требует выставленного текущего контекста).

QOpenGLFramebufferObject* fbo = nullptr;
connect( quickWindow, &QQuickWindow::sceneGraphInitialized,
[&] () {
fbo = new QOpenGLFramebufferObject( quickWindow->size(), QOpenGLFramebufferObject::CombinedDepthStencil );
quickWindow->setRenderTarget( fbo );
}
);

offscreenSurface = new QOffscreenSurface();
offscreenSurface->setFormat( context->format() );
offscreenSurface->create();

context->makeCurrent( offscreenSurface );
renderControl->initialize( context );
context->doneCurrent();


Рендеринг



Рендеринг необходимо осуществлять как реакцию на сигналы QQuickRenderControl::renderRequested и QQuickRenderControl::sceneChanged. Разница в этих двух случаях заключается в том что во втором случае необходимо дополнительно вызывать QQuickRenderControl::polishItems и QQuickRenderControl::sync. Второй важной особенностью является то что настойчиво не рекомендуется отсуществлять рендеринг непосредственно в обработчиках упомянутых выше сигналов. Поэтому используется таймер с небольшим интервалом. Ну и последней токостью является то, что, в случае использования shared OpenGL контекста, после рендеринга, требуется вызывать glFlush — в противном случае первичный контекст не видит изменений в FBO.

bool* needSyncAndPolish = new bool;
*needSyncAndPolish = true;

QTimer* renderTimer = new QTimer;
renderTimer->setSingleShot( true );
renderTimer->setInterval( 5 );
connect( renderTimer, &QTimer::timeout,
[&] () {
if( context->makeCurrent( offscreenSurface ) ) {
if( *needPolishAndSync ) {
*needPolishAndSync = false;
renderControl->polishItems();
renderControl->sync();
}
renderControl->render();
quickWindow->resetOpenGLState();
context->functions()->glFlush();
context->doneCurrent();
}
);

connect( renderControl, &QQuickRenderControl::renderRequested,
[&] () {
if( !renderTimer->isActive() )
renderTimer->start();
}
);

connect( renderControl, &QQuickRenderControl::sceneChanged,
[&] () {
*needPolishAndSync = true;
if( !renderTimer->isActive() )
renderTimer->start();
}
);


Ну вот в общем то и все, первая часть задачи выполнена.


Класс реализующий вышеприведенную концепцию доступен на GitHub: FboQuickWindow.h, FboQuickWindow.cpp

Коментарии, вопросы, здоровая критика в комментариях приветствуется.


Продолжение следует...


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


MugenMvvmToolkit — кроссплатформенный MVVM фреймворк

Релиз Rust 1.0 Alpha

С удивлением обнаружил, что это ожидаемое многими событие почему-то обошло Хабр стороной. Думаю, что для многих программистов, следящих за этим языком программирования, будет полезно узнать, что тот самый релиз версии Rust 1.0.0 состоялся 9 января. В этой версии наконец-то стабилизировали ядро языка и большую часть стандартной библиотеки, так что теперь можно начинать писать на Rust'е программы не боясь, что через неделю что-то сломается после обновления компилятора.

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


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


пятница, 9 января 2015 г.

Делаем отгружаемые сборки: взаимодействуем между доменами без маршаллинга

01 Ссылки для UX-специалистов

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







  • http://ift.tt/14zALuM — UX-раздел известного журнала о веб-технологиях и дизайне Smashing Magazine;

  • blog.uxpin.com/ — блог компании UXPin, в котором они помимо корпоративных новостей много пишут взаимодействии пользователей с интерфейсами;

  • usabilitygeek.com/ — блог, призванный объединить теорию и академические исследования с практикой и личными рекомендациям, для того чтобы улучшить удобство пользования веб-сайтами;

  • uxmag.com/ — журнал с полезными статьями о пользовательcком опыте. Все статьи пишутся специалистами со всего мира, но проходят редакторский отбор и коррекцию;

  • uxbooth.com/ — статьи от ux-сообщества и для него, ориентированные также и для новичков;

  • boxesandarrows.com/ — здесь помимо UX, множество материалов по дизайн-исследованиям и тестов;

  • http://ift.tt/1tSWmKx — раздел статей авторитетной Norman Nielsen Group об исселодваниях в области опыта пользовательского взаимодействия;

  • ia.net/blog — блог об информационной архитектуре;

  • http://ift.tt/14zALLo — раздел о UX популярного дизайн-блога;

  • uxcolombo.org/blog/ — цель этого ресурса — обучение дизайнеров и разработчиков для улучшения взаимодействия их продуктов и сервисов с пользователями;

  • uxmovement.com/ — блог, рассказывающий как плохие интерфейсы могут влиять на поведение пользваотелей;

  • 52weeksofux.com/ — экскурс-статьи в процесс дизайна для реальных людей;

  • http://ift.tt/1vR7VAm — ежедневная / еженедельная / ежемесячная рассылка материалов на UX-тематику;

  • http://ift.tt/14zAIzd — раздел статей по UX на блог-платформе Medium;

  • medium.com/design-ux — ещё одна ветка для UX-дизайнеров;

  • uxmyths.com/ — коллекция наиболее частых мифов о UX, объясняющих почему это неправда.





  • http://ift.tt/1pX6H27 — must-read библиотека для дизайнеров, разработчиков, продакт-менеджеров, UX-специалистов;

  • designprinciplesftw.com/ — супер сборник дизайн-принципов от лучших интернет-компаний;

  • uxporn.uxpin.com/ — колекция паттернов

  • tabpatterns.com/ — коллекция дизайнов для планшетов, разбитых по категориям;

  • pttrns.com/ — похожая коллекция, только с дизайнами для смартфонов;

  • zurb.com/responsive — каталог с примерами адаптивных дизайнов, с реальными примерами на сайтах;

  • littlebigdetails.com/ — сборник с обзорами маленьких, но интересных деталях в интерфейсах.





  • uxpin.com/ — инструмент прототипирования с широкими для этого возможностями и большой библиотекой ресурсов и шаблонов;

  • axure.com/ — один из известнейших инструментов для прототипирования, любимец проектировщиков и менеджеров;

  • invisionapp.com/ — мощный онлайн-сервис, с возможностью удобной командной работы над прототипами и пользовательскими опытом;

  • uxcheck.co/ — Chrome-плагин для проведения экспертной оценки по ключевым эвристикам Нильсена;

  • zeplin.io/ — инструмент для совместной работы дизайнера интерфейсов и front-end разработчика;

  • userium.com/ — чек лист по юзабилити для общих случаев.


Спасибо за внимание, в следующий раз будет подборка со свежими и наиболее популярными материалами из мира UX.


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Перевод] Год npm в цифрах: 2014

npm — это пакетный менеджер Node.js. С его помощью можно управлять модулями и зависимостями.

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


Ниже представлен набор показателей. Некоторые из них я отслеживаю, а некоторые просто решил посмотреть. Еще указано то, насколько они изменились с 1 января по 31 декабря 2014 года.


Количество пакетов в реестре:




1 января: 53 459

31 декабря: 115 194

Темпы роста: 2.1x.



Скачиваний за предыдущие 30 дней:




1 января: 149 822 000 (примерно)

31 декабря: 648 620 794

Темпы роста: 4.3x (рост на самом деле немного больше, это связано с тем, что недавно проходили новогодние праздники)

Количество талисманов:




1 января: 0

31 декабря: 1

Это долгая история, но у нас теперь есть вомбат и мы его любим. Спасибо, Джон!





Количество загрузок в будние дни (примерно):




1 января: 6 024 000

31 декабря: 25 000 000

Количество загрузок в выходные дни (примерно):




1 января: 3 000 000

31 декабря: 12 000 000

Мы перечислили их отдельно, потому что многих людей до сих пор удивляет то, что Node.js больше популярен в будние дни, чем на выходных. Люди используют npm чтобы делать по-настоящему серьезные вещи!


Почему число скачиваний растет в два раза быстрее, чем число пакетов? Потому что людей, просто использующих пакеты, больше, чем людей, участвующих в их разработке. Насколько точно — сказать довольно сложно. Вот некоторые показатели, которые мы попытались измерить:


Зарегистрированные разработчики:




1 января: 21 000 (очень грубая оценка)

31 декабря: 83 317

Темпы роста: 4x. На текущий момент регистрируются только те, кто собирается публиковать пакеты.

Еженедельные число уникальных посетителей сайта npm:




18 января (первый день, за который мы имеем данные): 113 000

20 декабря (последняя неделя перед праздниками): 264 000

Темпы роста: 2.3x

Всего уникальных пользователей на сайте npm в 2014 году:




5 444 000

Всего просмотров страниц в 2014 году:




35 000 000

Топ-10 стран, использующих npm:




1. США

2. Великобритания

3. Индия

4. Германия

5. Франция

6. Канада

7. Китай *

8. Россия

9. Япония

10. Бразилия

(* Китайские пользователи npm запускают множество зеркал, поэтому фактическое использование npm в Китае, вероятно, выше)


Как насчет программного обеспечения самого npm?


Общее количество коммитов во все репозитории npm:




2013: 919

2014: 3 360

Темпы роста: 3.6x

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


Уникальные IP-адреса, обращающиеся к реестру, за последние 7 дней:




1 402 000 (примерно)

Уникальные посетители сайта за последние 90 дней:




2 100 000

Всего репозиториев:




154

Открытых вопросов:




1173

Закрытых вопросов:




6889

Количество штатных сотрудников:




1 января: 0

31 декабря: 11

Остается только добавить: это был очень хороший год, и все это благодаря прекрасным пользователям, таким как вы, которые каждый день появлялись и пользовались нашими программами и сервисами! Мы очень счастливы, что вы это делали. С Новым 2015 Годом!


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Первый опыт разработки iOS-приложения и размышления о маркетинге и рекламе

… в общем создал я игру. А дело было так.

Несколько месяцев назад подошёл мой начальник и обрадовал, что с сегодняшнего дня, в дополнение к своим основным обязанностям, я должен буду делать iOS-приложения (не сильно сложные, но по работе необходимые), что Mac mini мне купили и что я самый опытный из всех по части продукции Apple (это правда, т.к. ваш скромный слуга уже четвёртый год ходит с 1-м iPad). Ну ладно.



Через две-три недели, когда был получен небольшой опыт в работе с Mac OS X, XCode и Objective-C, я понял, что было бы здорово создать своё приложение с нуля и познать процесс разработки от идеи до выкладывания в AppStore. Так я и сделал, принеся в жертву лень и свободное время по вечерам.


В качестве среды разработки (а дома у меня компьютера с MacOS X нет) была выбрана виртуальная машина VMWare с MacOS X Mountain Lion от ребят из iAtkos (на моём ноутбуке с Intel Core i7 машина работала весьма достойно). В качестве идеи была выбрана игра, которую я всё собирался сделать, да никак не доходили руки: простой плиточный пазл. Я рассудил, что для неопытного разработчика (это про меня) создать игровую механику будет не сложно (так и оказалось). Чтобы игра была уникальной, было решено использовать картинки, что рисует мой папа (да, он художник) в свободное от работы время для развлечения. А чтоб было совсем хорошо, было решено для некоторых пазлов показывать видео того, как они рисовались (такие ролики на YouTube многим нравятся и я не исключение).


Каркас игры был сделан быстро и началось создание дизайна, что далось, если честно, с трудом. За основу был взят мой старый набросок:


image



Магией Photoshop этот рисунок был превращён в такое:
image



Это не шедевр, но, как мне показалось, и не совсем кошмар, так что на этом варианте и остановились.

Когда игра была готова на 70%, то она была показана коллегам по работе, от которых были получены очень хорошие советы по графической части («ужасная иконка», «цвета надписей сменить» и т.д.). Кроме того, советовали быстрее выкладывать в AppStore, когда всё исправлю. Но я стал упрямиться, т.к. хотел приделать помощницу, которая бы при запуске программы рассказывала о том, что нужно знать пользователю. Так что релиз был отложен.


Музыка и звуки — очень важная часть программы-игры, поэтому решено было не скупиться и потратить денег. В итоге на сайте www.pond5.com было куплено медиафайлов на 2115 руб. Да, дороговато, поэтому музыку, которая сопровождает видео, было решено взять у хороших ребят из Destiny Records и OnAirStudio, про которых я случайно узнал от русского летсплейщика Артура (BlackSilverUFA), за что ему отдельная благодарность. Эти команды создают хорошую качественную музыку и позволяют использовать в своих проектах, при условии, что ты скажешь про них где-нибудь: внутри программы или в описании к YouTube-видео. Я поблагодарил их в разделе About.


В процессе работы над музыкой было решено купить для разнообразия лицензию разработчика Apple и проверить, как игра работает на физическом устройстве (мы к тому времени с коллегами купили iPhone 4 на четверых). Как выяснилось, плохо. Дело в том, что для сохранений я использую базу данных SQLite (с которой работаю, кстати, через http://ift.tt/K1V7Pu, что сильно упростило процесс разработки) и на физическом устройстве в эту базу ничего не писалось, хотя на эмуляторе всё было здорово. Помог сайт stackoverflow.com, на котом я узнал, что базу нужно копировать в директорию, доступную для записи. В итоге, в ViewDidLoad был добавлен код:



NSArray *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDir = [cachePath objectAtIndex:0];
gameSavesDB = [cacheDir stringByAppendingPathComponent:@"gameSaves.db"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:gameSavesDB]){
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"gameSaves.db"];
NSError *error;
[fileManager copyItemAtPath:databasePathFromApp toPath:gameSavesDB error:&error];
if (error != nil){
NSLog(@"[Database: Error]%@", error);
}
}




Больше в программе проблем не было и на физическом устройстве всё работало на удивление хорошо.

В качестве монетизации был выбран вариант с In App Purchase, т.к. реклама в мобильных приложениях мне не очень нравится. От том, как работать с In App, очень хорошо написал epazzz в статье «iPhone разработка: Интегрируем In-App Purchases». Но код и дополнительные сведения я всё же взял здесь (см. ответ пользователя Jojodmo): http://ift.tt/149vPMD. Это сильно упростило и ускорило разработку. В итоге получилась такая логика: в игре доступно 15 бесплатных пазлов. Потом появляется окно с очень грустным котиком, который предлагает разблокировать всю игру. После этого деньги предполагается не просить никогда.


image



Теперь игра была полностью готова и наступила пора выкладывания в AppStore. Проверка длилась 10 дней. Видимо, потому, что review проходила как сама игра, так и In App Purchase. Один раз вернули со статусом Metadata Rejected и цензор написал, что он не понял, как у меня в программе In App найти. Видимо, в полях, помеченных как Notes, надо было не смайлики оставлять, а писать чёткую инструкцию человеку. Бывает. После того, как шаги были предоставлены, игра быстро появилась в магазине. И наступила последняя фаза…

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

1. Были отправлены запросы на БЕСПЛАТНЫЙ обзор на сайты: appsafari.com, tuaw.com, appstoreapps.com, 148apps.com, mobilestartupz.com, iPhones.ru, appadvice.com.

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

2. Была сделана на 300 рублей реклама на Facebook. Это принесло стабильные 3 скачивания в день. С социальными сетями вообще в плане рекламы мобильного приложения эффективно работать не получилось. Но, наверное, дело во мне, т.к. я ими не пользуюсь и слабо представляю, как всё это работает.

3. Говорят, что можно сделать пост на pikabu и 9gag и это увеличит количество скачиваний. И есть даже положительный опыт. Но этими сайтами я не пользуюсь, на pikabu меня за дело обругали, так что я решил идею оставить на потом.

4. Что увеличило количество скачиваний вдвое, так это пятое обновление, которое принесло оптимизацию игры под экран iPad (раньше была лишь iPhone-версия).

5. С помощью сайтов sensortower.com, searchman.com и www.mobiledevhq.com была проведена работа над ключевыми словами. Также в iTunesConnect в поле Name помимо названия приложения были тоже вставлены ключевые слова (т.е. вместо, например, «От Севильи до Гренады» стало «От Севильи до Гренады – отличная головоломка для девушек» (эти названия не настоящие, а просто пример)).

6. Кроме того, по последним слухам, сильно влияет на скачиваемость приложения то, что страница в AppStore переведена на разные языки. Для меня это русский, английский и французский. Ничего про эффект сказать не могу, т.к. последний язык был добавлен совсем недавно и пока во Франции пользователей нет.

7. И конечно стандартное: наличие сайта со ссылкой на программу и промо-видео на YouTube. Сайт мы сделали вдвоём с коллегой по работе (у меня на работе очень много хороших людей), а видео было записано с помощью встроенных средств Mac OS X Yosemite, обработано на iPad в iMovie, а затем отправлено в Photoshop для накладывания фона. В итоге, получилось так:



И последнее на сегодняшний день, что было сделано — добавлена аналитика. Это было очень легко сделать с помощью сайта Parse.com. Легко, так как там очень продуманный интерфейс и пошаговая инструкция с указаниями, что конкретно надо делать. Так что аналитика добавилась за несколько минут и теперь я буду хотя бы знать, сколько пользователей дошли до диалога In App, а сколько не смогли решить даже первой головоломки.


В качестве завершения: стоимость разработки. Как видите, удалось уложиться в небольшую сумму:

— 2 000 рублей на iPhone 4;

— 100$ (по старому курсу) на лицензию разработчика;

— почти 2 115 рублей на звуки и музыку;

— 300 рублей на рекламу на Facebook;

— 340 рублей на тортик для коллег.


В Сети прочитал, что минимальная стоимость разработки iOS-приложения составляет 5000$. Видимо, когда высчитывалась эта сумма, учитывались какие-то ещё параметры, т.к. в моём случае явно вышло меньше. С другой стороны, у меня были очень хорошие условия разработки: по времени ограничения не было, недостатка в тестовых устройствах также не было, т.к. на работе есть весь ассортимент устр… В общем, не было проблем с устройствами. Тестирование проводилось сообща, вместе с коллегами, а перевод на английский, французский и немецкий делали две коллеги-переводчицы, за что им от меня огромная благодарность. А на украинский язык я перевёл сам (хотя пока в игре есть лишь русский и английский; остальные языки приделаю позже). Дизайн же создавался мною в Photoshop. Когда возникала необходимость в новых картинках (кнопки, котики, девушка-помощница), я объяснял всё моему художнику и он рисовал всё, что нужно. Потом, после бурного всплеска эмоций, картинки корректировались, дорисовывались и отдавались мне. И всё, естественно, бесплатно.


Заработка пока нет. Думаю, может, всё-таки дать людям выбор: либо купить In App, либо включить показ рекламы (несмотря на то, что в начале статьи я казал, что против неё). Буду рад доброму совету.


На этом прощаюсь. Кто прочитал – молодец, а кто устал – искренне прошу прощения. Пока-пока-пока.


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Зачем vi-топор программисту 21-го века

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

Git очень быстро завоевал мою любовь и с тех пор я даже не представляю себе свою работу без него.


Однажды, играясь и пробуя разные команды, я случайно запустил режим редактора, а Git, как оказалось, по умолчанию использовал Vim, который я до того времени в глаза и не видел. Ну и как обычно происходит первое знакомство с этим редактором? Правильно — с недоумением и перезагрузкой терминала. Банально — выйти из редактора я так и не смог и честно, даже подумал, что редактор тупо глючит. Я даже помню, как-то удивился — как же блин так получилось, что такие умные чуваки, создавшие такую мощную штуку, как Git, могли выбрать такой архаичный, тупой, непонятный и некрасивый (как мне поначалу показалось) редактор?







Но потом мне стало любопытно, я начал копаться. Признаюсь честно, путь к преодолению собственной лени и наработанных привычек был непрост и очень долог. Но я ничуть не жалею о потраченном времени и нервах. Сейчас я использую (и использовал) Vim-режим практически везде, где это возможно — WebStorm/RubyMine/PyCharm, Sublime Text, Visual Studio, Atom. Vim-режим у меня активирован в Терминале и даже в Браузере.

Да, да, как оказалось, зная Vim-овы команды можно очень эффективно переключаться между вкладками, переходить по ссылкам, листать вниз и вверх, искать текст на странице и многое, многое другое.


Под Chrome существует аж целых три расширения — наиболее популярный Vimium, менее популярный и немного подустаревший Vrome и бурно развивающийся, молодой cVim. Я начинал с первого, потом перешел на Vrome. Дело в том, что Vrome предлагает обалденную фичу — редактирование текста в стороннем редакторе. То есть идешь, к примеру, на StackOverflow, чтобы задать вопрос, переходишь в область текстового поля и… нажатием комбинации клавиш открывается Vim — можно вбивать текст, используя всю его мощь. При сохранении текст автоматически попадает обратно в браузер. Фантастика. К сожалению, Vimium встроенной такой поддержки пока не имеет. Хотя в остальном во многом превосходит Vrome, я недавно снова перешел на Vimium и, как оказалось, многие баги были пофиксены, добавилась функциональность и т.д. Хотя без поддержки внешнего редактора, конечно, приходится страдать. cVim — несмотря на свою молодость, достаточно мощный и быстро развивающийся проект, очень хочется надеется, что автор и участники проект не забросят, как это произошло с Vrome.

Я не очень часто использую Firefox, но насколько я знаю, там рулит Vimperator.


Vim — обалденная все таки вещь, единственный недостаток Vim-а — привыкнув раз, привыкаешь на всю жизнь. К примеру, мне теперь не хватает Vim режима в Скайпе, в Ворде, в Slack и т.д. Интересно, что многие веб-сайты внедряют базовую vim-навигацию — gmail, trello, github и т.д.


Если вы хоть раз пробовали Vim и так и смогли заставить себя привыкнуть, вы обязательно должны постараться еще раз. Если вы хотите постичь дзен Vim-а — наберитесь терпения. Запустите и пройдите vimtutor, поиграйтесь в Vim Adventures. Старайтесь не нервничать оттого, что все время приходится вспоминать/искать искомую комбинацию клавиш. Распечатайте шпаргалку. Поначалу вам будет казаться, что вся эта овчинка не стоит выделки и Vim никоим образом не делает вас более продуктивным, а все даже с точностью наоборот. Поверьте мне на слово, понадобятся месяцы чтобы ощутить всю прелесть Vim-а. Через какое-то время вы даже не будете задумываться — пальцы сами будут бегать по клавиатуре, а для непосвященного наблюдателя ваши действия будут выглядеть сущим колдовством. Кто-то даже как-то пошутил — мол любая мало-мальски значимая Vim-ова комбинация сойдет за Fatality в Mortal Kombat.


Ну что, заинтригованы? А теперь давайте поговорим о настоящем редакторе (шутка).


С тех пор, как я в первый раз открыл для себя Vim прошло, много времени, но постепенно мне стали открываться и недостатки Vim-a. Дело в том, что Vim — это редактор. Сделать из него полноценный IDE не скажу что прям невозможно, но чертовски сложно. Да и потом, мы же не только текст редактируем, нам нужен полноценные поиск и замена, intellisense, файловый менеджер, встроенная поддержка VCS, желательно окно терминала, многоязычность и прочее и прочее. Да, у Vim-а куча плагинов, их можно подключать, их можно до бесконечности настраивать и так далее, но в сущности Vim так по большому счету и останется — редактором. В этом плане Sublime даже ничуть не хуже. Я обожаю IDE от JetBrains. Webstorm, к примеру, просто улетная штука. Что плохо? А то, что и в том и в другом поддержка Vim-режима не без нареканий.


Итак, хочется иметь среду с поддержкой Vim режима, но при этом:



  • с более удобным встроенным языком конфигурирования;

  • с удобным менеджером плагинов и достаточным разнообразием оных;

  • с поддержкой нескольких языков (input and localizations);

  • с удобной навигацией по командам (аля Sublime).




И что в итоге мы имеем? А имеем мы Emacs. Да, да, не удивляйтесь.

К изучению Emacs меня подтолкнуло праздное любопытство, а еще коллега, который до Emacs лет десять пользовался Vim-ом, ну и знакомый, у которого я утащил к себе конфигурацию для Vim-а (а в последствии и для Emacs-а).


Поначалу злобный Emacs меня к себе совсем не подпускал. Я еще шутил на работе, мол у Emacs-а такого огромное эго, что оно не влезает в мой компьютер. Чтобы попробовать, я скачал голый Emacs, запустил. Посмотрел. Не понравилось. Потом попробовал скачать так называемый Starter Kit — и оно не понравилось. Ну не могу я без Vim режима, хоть тресни. И вот тогда-то я и открыл для себя Evil-mode. И тут я понял, как же все таки был неправ в своей лени и надо было попробовать Emacs раньше.


Я только-только перешел на Emacs и, пожалуй, не стану давать каких либо советов. Скажу только, что я очень быстро осознал насколько у него гибко-настраиваемая среда. Emacs — это не редактор, это скорее конструктор, из которого можно собрать себе IDE, текстовый процессор, органайзер на свой цвет и вкус. К примеру: я подумал, а почему бы мои записки Evernote не вбивать прям в Emacs? Нашел плагин, установил, настроил — пользуюсь. Здорово. Второй пример: мне приходится достаточно часто писать на английском и пользоваться тезаурусом. Тут оказалось под это плагинов аж несколько — пришлось выбирать. Тот, что я выбрал, отображает окно со списком слов-вариантов. Но мне же нужна полная автоматизация; нужно, чтобы при открытии окна с вариантами курсор сам прыгнул в то окно. А потом, после того как я выберу подходящий вариант, мог бы легко заменить им искомое слово и закрыть окно уже за ненадобностью. Оказалось, подобные трюки очень легко спрограммировать. И теперь мне не приходится лезть в интернет за тезаурусом, а поиск и подбор вариантов занимает буквально секунды.


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


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Прокачай SNMP на устройствах Huawei и H3C

Бесконечно можно делать три вещи: смотреть, как горит огонь, смотреть, как течет вода, — и говорить о безопасности небезопасных протоколов. Мы уже рассказывали о сканировании корпоративных сетей, сетевых устройств и Cisco IOS. На этот раз предлагаем вам историю о протоколе SNMP, а точнее — о работе по этому протоколу с сетевым оборудованием HP/H3C и Huawei. Данные устройства позволяют получить доступ к критически важной информации, обладая минимальными правами. Эксплуатация уязвимости позволяет злоумышленнику проникнуть в корпоративные сети коммерческих компаний и технологические сети операторов связи, использующих эти широко распространенные устройства.

image


В 2003 году Huawei Technologies и 3Com основали совместное предприятие H3C. В 2007 году компания 3Com выкупила у Huawei ее долю, а в 2010 году вошла в состав HP, которая автоматически получила и H3C. Таким образом, уязвимым оказалось сетевое оборудование сразу нескольких вендоров — 3Com, H3C и HP, Huawei. Устройства эти используются в тысячах компаний, от небольших предприятий до крупнейших провайдеров.


Какую же критически важную информацию они выдают? Речь идет о пользовательских данных, хранящихся в базах h3c-user.mib и hh3c-user.mib. Эти mib определяют объекты для «Manage configuration and Monitor running state for userlog feature». В новой версии ОС доступ к ним должен был быть разрешен только с read-write community string. Однако этого не было сделано, и получить информацию можно и с community string с правами read-only.


В этих базах содержится следующая информация:



  • имена локальных пользователей,

  • их пароли,

  • тип шифрования пароля,

  • уровень привилегий, которым обладает пользователь.




И чтобы все это узнать, необходимо лишь угадать read-only community string, которая очень часто настроена по умолчанию как «public».

За эту информацию на устройствах отвечает OID: 1.3.4.1.4.1.2011.10 и OID: 1.3.6.1.4.1.25506.

Непосредственно за саму информацию о настроенных локальных пользователях отвечает OID: 1.3.6.1.4.1.2011.10.2.12.1.1.1 и 1.3.6.1.4.1.25506.2.12.1.1.1.


В ответ на запрос с этими OID мы получим (H)H3cUserInfoEntry, которая содержит следующие значения:


• (h)h3cUserName — The name of local user, it must be unique

• (h)h3cUserPassword — The password of local user, default is null

• (h)h3cAuthMode — The encrypting type of password:



  • 0: password simple, means password is clean text.

  • 7: password cipher, means password is encrypted text.

  • default is 0




• (h)h3cUserLevel The privilege of local user the value range is from 0 to 3, and 0 is minimum, 3 is maximum. default is 0.

В приведенном ниже примере snmpwalk вызывается с ключом –Cc, так как работа идет с динамическими индексами. Если выполнить запрос без этого ключа, может возникнуть ошибка «Error: OID not increasing».


image


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


image


Но при этом через SNMP пароль все равно указывается в открытом виде (вероятно, это зависит от конкретного устройства):


image


Итак, мы смогли получить учетные данные локальных пользователей, в том числе и с максимальным уровнем привилегий (пользователь «admin» с уровнем привилегий «3»). Теперь остается лишь попробовать подключиться к устройству через SSH или Telnet:


image


Нам повезло и доступ на сервер по SSH не был запрещен. Но если вдруг по SSH или Telnet зайти не удается…


image


… всегда можно попробовать зайти через web (картинка кликабельна):


image


image


Теперь посмотрим на другой пример.


image


В данном случае мы получили пароли в зашифрованном виде. Huawei может использовать для шифрования паролей алгоритмы AES256 или DES. При этом в схеме с алгоритмом DES используется одинаковый ключ шифрования на всех уязвимых устройствах и не используется соль при шифровании. В результате пароль может быть легко дешифрован, о чем написали Roberto Paleari и Ivan Speziale из компании Emaze Networks в 2012 году.


image


image


Итак, можно открывать любимую консоль и пытаться подключиться с полученными данными по SSH или Telnet:


image


Или, как мы уже сказали, если доступ по этим протоколам ограничен, всегда можно попробовать зайти через другой протокол:


image


Следует заметить, что в схеме шифрованием с AES256 тоже есть проблемы: в 2014 году те же ребята из Emaze Networks опубликовали еще одну заметку, в которой рассказывают о том, как все плохо.


Результаты поиска в Shodan наглядно демонстрируют, насколько популярна данная уязвимость:


image


image


image


Так как Huawei — компания китайская, неудивительно, что большая часть всех доступных устройств находится в Китае. Но в России тоже не все гладко:


image


image


image


Надо сказать, что первым о данной уязвимости написал Kurt Grutzmacher еще в 2012 году. В том же году он выступал на конференции Bay Threat, где подробно описал проблему и то, чем она грозит. Производители оборудования выпустили патчи для своих устройств — но, как это обычно бывает с сетевым оборудованием, большое количество устройств остается уязвимым до сих пор.


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


Все это еще раз подтверждает прописную истину: небезопасные протоколы несут в себе большую опасность. Для того чтобы попасть в корпоративную сеть, не нужно использовать хитрые схемы со сложными эксплойтами: достаточно одного протокола SNMP со стандартной community string с минимальными правами read-only и еще одного протокола для доступа на устройства — SSH, Telnet или web. Причем, как показала практика, если доступ по Telnet или SSH на большинстве устройств ограничен, то по HTTP — входи кто хочет.


И еще один «приятный бонус». При настроенном сервисе регистрации попытку зайти на устройство по SSH, Telnet или web можно будет увидеть, например, на Syslog-сервере. Но для запросов по SNMP подобных сообщений не будет, и можно даже не узнать, что кто-то получил учетные данные или натворил что-нибудь еще (например, изменил конфигурацию устройства).


Как защищаться




Достаточно просто. Во-первых, надо выключить сервис SNMP.

image


Если этот протокол все же необходим, то использовать SNMPv3. Если и это невозможно, избегайте использования стандартных community string — public и private.


image


Можно исключить объекты таблицы (H)H3cUserInfoEntry из доступа с помощью команды excluded, а также запретить доступ к устройству с правами read-write.


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


image


Автор: Евгений Строев, исследовательский центр Positive Technologies


Ссылки:



http://ift.tt/1xP0Vp3

http://ift.tt/1xP0Vpd

http://ift.tt/14yWIKg

http://ift.tt/14yWG5g

http://ift.tt/1dMNmeR

http://ift.tt/14lgeV2

http://ift.tt/1xP0X0j

http://ift.tt/1xP0Txs

http://ift.tt/14yWGSG

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Интерактивные карты кибератак в реальном времени

«Кибервойны — это уже реальность и нам, простым смертным, остается только наблюдать за ними...»

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

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



«Find out where you are on the Cyberthreat map» или «Узнай, где сейчас кипит кибервойна»

Начнем с отечественного ресурса, детища лаборатории Касперского — проект Узнай, где сейчас кипит кибервойна.

Визуализация очень красочная и удобная для просмотра, поэтому залипать на «Земной шар» можно долго (не забудьте запастись чаем).


Find out where you are on the Cyberthreat map
image


«Norse Live Attack Map»

Однажды, крупная американская компания Norse поставила кучу ханипотов и с открытыми портами и прочими плюшками и сделала ресурс Norse Live Attack Map, где показала, что весь мир «дербанит» их ханипоты (особенно Китай).

Даже крупный новостной портал Daily Mail в своей статье ссылался на ресурс Norse Live Attack Map (стоит отдать должное — в статье фигурирует и отечественный продукт лаборатории Касперского).


Norse Live Attack Map
image




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

«Top Daily DDoS Attacks Worldwide»

Ресурс Top Daily DDoS Attacks Worldwide от корпорации Google тоже не отстает в наглядности от своих конкурентов — все также залипательно, информативно. Заодно есть и галерея «красивых атак» и выборка новостей по атакам.


Top Daily DDoS Attacks Worldwide by Google
image


«Cyber Threat Map by FireEye»

И еще один ресурс от крупной компании FireEye Cyber Threat Map.

Карта сама по себе менее информативная, однако тоже красочная, да и к тому же, можно подписаться на рассылку — будете в курсе крупных атак)


Cyber Threat Map by FireEye
image


«Security Tachometer by Deutche Telekom»

Security Tachometer от крупнейшей в Европе телекоммуникационной компании Deutche Telekom.

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


Security Tachometer by Deutche Telekom
image


«Cyberfeed Live Botnet Map by AnubisNetworks»

Проект Cyberfeed Live Botnet Map от компании AnubisNetworks показывает нам статистику заражений, приводя рейтинг ботнетов (zeus, andromeda и прочие).


Cyberfeed Live Botnet Map by AnubisNetworks
image


«Real-time Web Monitor by Akamai»

Ребята с компании Akamai тоже не отстают — сервис Real-time Web Monitor тому доказательство.


Real-time Web Monitor by Akamai
image




Кстати, у них есть и другие визуальные карты и графы

«Global Activity Maps ATLAS»

Проект ATLAS от Arbor Networks.

Очень неплохой сервис, хоть и визуально скуден. зато отчеты по атакам, сканам, ботнетам можно выгружать в разных форматах.


Global Activity Maps ATLAS
image




«Global Botnet Threat Activity Map by Trend Micro»

Global Botnet Threat Activity Map от известной компании Trend Micro.

Визуально скудно, пару графиков по ботнетам.


Global Botnet Threat Activity Map
image


«Internet Malicious Activity Maps by TeamCymru»

Internet Malicious Activity Maps от Team Cymru Research.Ребята сделали мувики по дневной активности — вышло «дешево и сердито».


Internet Malicious Activity Maps by TeamCymru
image


«F-Secure Global Maps»

Визуально-пестрые карты от компании F-Secure — Globe и VirusMap.


F-Secure Global Maps
image




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


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


JSON, который можно комментировать

Не все JSON нельзя комментировать (например, Хром[иум] вполне переносит комментарии в manifest.json), но в стандарте не предусмотрены комментарии к нему. Поэтому ряд функций в NodeJS не обрабатывают комментарии в формате JS и считают их ошибкой. Точно так же, AJAX с форматом JSON принимает их за ошибку. Поэтому для конфигурационных файлов в формате JSON имеется масса неудобств при попытках их использовать как человеко-читаемые файлы. Может быть, это иногда хорошо. Если хотим прокомментировать, то будем вынуждены оформить комментарий под или над строкой как «ключ-значение».

...{...
"some-key_comment":"my comment for key and value",
"some-key":"some-value",
...}...


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

...{...
"some-key":"some-value", //какой-какой key?? Ай, комментарии - нельзя!
...}...




Придумаем JSON-подобный формат с комментариями в стиле JS, чтобы их можно было выполнять как JS, а, очистив от комментариев — читать как JSON. ("TL:DR: покажите мне код.")



Сыр-бор и источник




Кстати, Дуглас Крокфорд, который это всё устроил, в 2012 году объяснил: )

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


Допустим, вы используете JSON для хранения конфигурационных файлов, которые привыкли комментировать. Вставьте любые комментарии, как вам нравится. Затем пропустите их через JSMin перед работой JSON-парсера.





Сделал он это на G+, где можно ставить только «плюсы», а комментарии закрыл. Так что, какова бы ни была реакция общества под объяснением, мы увидим только «плюсы» (или смотреть у тех, кто расшаривал этот пост).

И цитата Крокфорда из другого места:



Основная причина, отчего я удалил комментарии — были люди, которые пытались парсить данные на основе комментариев, что полностью ломало совместимость. Я никак не мог контролировать их, поэтому лучшим выходом было комментарии удалить.



Поэтому дальше читаем, кликнув и согласившись на обещание:






«Обещаю, что я буду осторожен и не буду использовать комментарии для парсинга данных!



Всё уже сделано до нас




В том и дело, что требуется ещё один парсер, а так — большой проблемы нет. И проблема этим не ограничивается — иногда надо файл слегка изменить, оставив комментарии. Первую часть (парсер) решили, например, через JSON.minify(). Вторую и ряд других проблем (концевые запятые или вообще без них, многострочные комменты, ключи и строки-значения без кавычек) — не поленились решить в Hjson, потратив 750 строк на код JS (с комментариями на 10-15%).

Стоп, а нужно ли это вообще?




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

Есть ещё хакеры, которым подойдёт совершенно хакерский, валидный способ записи JSON с последовательным повторением одинаковых ключей (в JS+»use strict" даст ошибку). Значение первого ключа в большинстве парсеров не сохранится, поэтому его (и все такие, кроме последнего) можно использовать как комментарии. Способ тоже страдает «машинностью».



...{...
"some-key":"comments_comments",
"some-key":"some-value",
...}...




Итого, не все будут за «ещё один формат, 16-й по счёту». Любая попытка построить, а тем более, применить конвертор форматов приведёт к игнорированию некоторой частью девелоперских юнитов данного формата. В тех же индивидуумах, в которых странным образом сочетаются осколки разных миров, которые ещё не определились со своей сущностью, процедуры конвертации покажутся полезными. По крайней мере, на первых порах, по мере превращения.

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


Мост между роботами и людьми




Можно придумать плагин к Grunt/Gulp (например, grunt-strip-json-comments, Gulp...) для очистки файлов от комментриев. Но суть действия сводится к небольшому (до 1 К) регулярному выражению, которое проще написать в Gruntfile.js, чем в него же вписывать ещё один плагин. Более того, такое же выражение нужно и для JS на клиенте, чтобы читать тот же JSON, поэтому от его явного вида мы всё равно не убежим.

Методы для преобразований форматов собраны в объект jsonComm, который работает в среде Javascript. Для решения частных задач не нужен весь объект — не всегда имеет смысл брать в проект все методы. Например с задачей простого удаления комментариев (как в gulp-strip-json-comments) справляется метод, состоящий из одного регулярного выражения (jsonComm.unComment(), до 1 КБ несжатого кода; пример далее; в тестовом разделе проекта jsonComm есть тесты и бенчмарки для оценки корректности и быстродействия), которое даже компилировать не надо, если нет цели применять разные настройки правил.


Настройки могут быть, к примеру, такие. Каким символом отмечать начало комментария? Если в среде чистого JS есть уверенный ответ — "//", то сторонники Пайтона или YAML скажут — "#". Попытки объединить непримиримых приводят к настройкам правил и к конверторам — тем самым, с которых, в том числе, начали. В среде адептов JS нет надобности в настройках, и они выжгут из проекта упоминание о "#". Потому что нельзя тратить 36 микросекуд (микро-) на генерацию регекспа ради лояльности к такой ереси. Лоялисты — тоже выжгут, но удлинят регексп и станут тратить 0.1-0.5 (условно) микросекунд (микро-) уже не на генерацию, а на каждый цикл перекодировки. За это их ненавидят пуритане. Ведь роботы мыслят гораздо быстрее, и им медлительность видится в другом масштабе.


Какие задачи можно решать при комментировании JSON?



  • просто читать в JS или NodeJS формат jsonComm (с комментариями), удалять из них комментарии и далее верифицировать как обычный JSON в JSON.parse(); то же самое, что делает большинство проектов по добавлению комментариев в JSON. Работает быстро (десятки-сотни мкс).

  • читать не JSON, а файлы JS (с кодом) чтобы из оставшейся части взять некоторые константы как настройки (например, в NodeJS), когда файл JS будет их тоже использовать при своём исполнении в другом месте (на клиенте) — своеобразный шаблон с упрощением структуры конфигурации;

  • как в предыдущем пункте, но уже хочется изменить некоторые настройки после прочтения (например, в Ноде обновить номер сборки или внести настройки конфига), чтобы далее JS на клиенте, ничего не подозревая, использовал их. Это — аналог шаблона на чтение-запись.




Здесь — не все мыслимые задачи, но группа, достаточная для простого конфигурирования проекта. Вместо Yaml с комментариями или костыльных комментариев в чистом JSON — пишем jsonComm с расширением *.js, который может или читаться как JSON (на сервере, при сборке проекта или на клиенте), или выполняться как JS, имея комментарии в JS- или YAML-стиле.

Задачи разделяются на 2 практических случая — когда нам не нужно редактировать свой jsonComm, и когда редактировать нужно, при этом оставляя все комментарии. Когда происходит только чтение (это же — случай клиентского AJAX), ограничиваемся единственным методом jsonComm.unComment() c одним регекспом, и далее — JSON.parse().


Случай записи изменённых значений или ключей потребует небольшой процедуры парсинга текстового файла JsonComm (с комментариями, без их удаления) или JS, чтобы точечно изменить требуемое. Манипуляция возможна для файлов "*.js", если коды языка в них не будем трогать скриптами — требуется лишь не ошибаться в записи значений ключей. К необходимым методам добавляется второй: jsonComm.change() .


Какие ещё задачи можно решать при комментировании JSON?

Задачи академического типа:



  • получить «валидный» доступ к комментариям jsonComm, переведя их сначала в пары «ключ#»-«комментарий», выбрав основу ключа из той строки, возле которой он найден, а затем, после парсинга из правильного JSON — обрабатывать их далее (например, переводя в другой формат);

  • работать с Yaml напрямую (но теряем признанную браузером/средой JS основу для валидации)

  • взаимное преобразование в Yaml и обратно через выше сделанный валидный JSON;

  • то же для XML; тогда получится кластер из четвёрки языков описания данных, 2 из которых признаны в браузерах и многочисленных вычислительных средах.




Особенность этих задач — практической необходимости в них нет, но видя нишу, место под них зарезервировано (функции toYaml, toXml, fromYaml, fromXml, to; последняя — это «в jsonComm»). Без комментариев — такой кластер и без того уже есть в работах других библиотек. Чтобы влиться в него с комментариями, нужно начать хотя бы с функции перевода комментариев jsonComm в один из валидных и признанных форматов. Очевидно, первый кандидат — JSON.

Первое же знакомство со способами комментирования создаёт много вопросов — к каким ключам привязвать комментарии до найденной пары, а каким — после? Например, комментарии после разделителя-запятой, но стоящие на той же строке, обычно относятся к предыдущей паре, поэтому на разделитель будет влиять и окончание строки. Второе: многострочные комментарии логически могут относиться к разным смежным парам. Третье: а к чему относятся комментарии в массивах? Их ключи выражены неявно, и логично бы создать рядом лежащий массив. А если он многомерный и с редким заполнением? Четвёртое: комментариев на строке может быть несколько; пара может быть растянута на 3 и более строк.


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


Грамматика jsonComm




Чаще всего встречаются пары в файлах JSON, зписанные на отдельных строчках:

<набор пробельных отступов>"<ключ>": <значение>




Значение — строка в кавычках или другие термы по всем правилам JSON. Ключ — любая строка, лишь с особым экранированием кавычек внутри себя. Между элементами могут быть пробельные символы, а разделяются пары запятыми или скобками, которые могут стоять где угодно до или после пары, в том числе, на соседних строках.

У нас будет очень похожий формат (jsonComm), с той разницей, что на месте пробельных символов могут быть комментарии 2 типов.


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


Далее, при решении творческой задачи по вопросу того, к какой паре отнести комментарии, расположение разделителя и переносов строк снова будет иметь значение. Для просто удаления комментариев — оказывается, что переносы строк не важны (не следует лишь удалять концевой перенос однострочного комментария).


С учётом сказанного, основная конструкция грамматики jsonComm выглядит так:



(("{" | "[" | ",")<пробелы>)
<пробелы-комменты>
(<пробелы>"<ключ>"<пробелы>)
<пробелы-комменты>
(<пробелы>(":")<пробелы>)
<пробелы-комменты>
(<пробелы><значение><пробелы>)
<пробелы-комменты>
|
<пробелы-комменты>
(<пробелы><значение><пробелы>)
<пробелы-комменты>
(<пробелы>("}" | "]" | ","))




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

Похожая, более сложная схема нужна будет для вставления комментариев-значений (функция jsonComm.comm2json() ). В ней из jsonComm вида



...
,"some-key":"some-value" //comments_comments
...}...




создаём

...
"some-key#":"comments_comments",
"some-key":"some-value",
...}...




или без строчки с ключом для комментария. Если в области текста, относящейся к паре, встретилось несколько комментариев, всех их копируют в значение «some-key#». Но если комментарий встретился не в районе пары (в массиве, до или после всех скобок), он игнорируется. Все символы комментария приходится преобразовывать в валидные для JSON. Например, табы — в "\t", "\" — в "\\",….

Как на практике содержать JsonComm?




До сих пор мы могли записать без проблем и плагинов только JSON со всеми оговорками отсутствия комментариев или с присутствием, но в виде значений (или править JS как текстовые файлы, или хранить в БД). Сейчас будем пользоваться изменяемыми (для NodeJS) файлами jsonComm, имеющими расширение *.js.

Выявлены 2 практические ниши применения JsonComm-файлов: на чтение конфигураций, оформленных с комментариями, на обновление конфигураций, и одна академическая — конвертор форматов.


Если файлы нужно только читать (клиентский JS и прочее), читаем их как xhr.responseText в AJAX или как *.js и преобразуем JsonComm в объекты-структуры с валидацией через JSON.parse().


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


Нет проблем добавить пайтоновский стиль однострочных комментариев (#comments_comments). Но тогда не будет работать способ чтения как файла *.js. В коде проекта заложена возможность отключить синтаксис "#" у комментариев (на начальном этапе компиляции регекспа).


Простые случаи, когда это нужно:


* В сборщике проекта на Grunt/Gulp/… вычисляем новый номер версии и запоминаем его в тот же файл конфигураци.


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


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


Реализация




Чтобы долго не крутить циклы, преобразование выполняется «одним махом» на регулярных выражениях.

Выкусывание комментариев




Преобразователь фактически работает как цикл по строкам, методично выкусывая комментарии и пропуская допустимые фрагменты JSON. На его базе несложно построить и распознаватели текста комментариев, чтобы их сохранять в особые ключи-значения. Таким способом, мы допускаем комментарии для дальнейших операций, но не для того, чтобы «нарушить совместимость» (при желании — всегда можно), а чтобы код с комментарием был более удобной записью хуже читаемого выражения из 2 пар «ключ-комментарий» и «ключ-значение».

Не



"ключ_": "комментарий",
"ключ": "значение",




, а

"ключ": "значение" //комментарий


Решение выполняет также задачу по распределению ответственности за валидность кода. Всё, что относится к комментариям, контролируется визуально и с подсветкой синтаксиса в IDE разработчиком. Правильность остального JSON разбирает стандартный парсер JSON.parse().


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


('\n'+строки_файла).replace(/(^|\r?\n)(([^"\r\n:]*"(\\"|[^"\r\n])*"|[^"\r\n:]*):?([^"\r\n]*"[^"\r\n]*"|[^"\r\n]*)[^\/"\r\n]*?|[^\/"\r\n]*?)(\/\*\*\/|\/\*([\s\S]?(?!\*\/))+.{3}|\/\/[^\r\n]*)/g,'$1$2')


Для понимания, как оно устроено, обратим внимание на функциональные части:


(^|\r?\n) — захватывающие скобки для отображения предыдущего переноса строки.

Следующая за ним скобка и её пара — ...[^\/"\r\n]*?) — вторые используемые для копирования захватывающие скобки.

"(\\"|[^"\r\n])*" — ключ или строка в кавычках; если кавычек нет — далее ищется альтернатива из просто


\s*\/\*\*\/|\s*\/\*([\s\S]?(?!\*\/))+.{3} — парсер многострочного комментария.

\/\/[^\r\n]* — парсер однострочного комментария до конца строки.


С выкусыванием комментариев в конце строки у этого несложного выражения — всё отлично. Хуже дело — с выкусыванием комментариев со звёздочкой между ключами и значениями. Можно пренебречь и не писать таких комментариев. Тем более, что у «конкурента» YAML имеются только концевые. Но, имея функциональные части, уже можно построить более сложное выражение, чтобы не накладывать таких ограничений. При этом придётся не просто оставлять «всё до комментария в строке», но и между ними — усложняются оставляемые фрагменты. Фактически, это — вся jsonComm.unComment(jsonCommString). Именно эту строчку можно копировать в Gruntfile.js вместо подключения модуля, чтобы очистить строку JSON от комментариев.


jsonCommString.replace(/(?:(?:((?:\{|,)\s*)(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*(\s*"(?:\\"|[^\r\n"])*"\s*)(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*(\s*:\s*)(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*(\s*(?:[0-9.eE+-]+|true|false|null|"(?:\\"|[^\r\n"])*"|(?!:\{|:\[))\s*)(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*(\s*(?:\}|(?!,))\s*)?)+?|(?:((?:\[|,)\s*)(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*(\s*(?:[0-9.eE+-]+|true|false|null|"(?:\\"|[^\r\n"])*"|(?!:\{|:\[))\s*)(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*(\s*(?:\]|(?!,))\s*)?)+?|(?:(?:\s*(?:\/\/|#)[^\r\n]*(\r?\n|$))*(?:\s*\/\*\*\/|\s*\/\*(?:[\s\S]?(?!\*\/))+.{3})*)*\s*)/g,'$1$2$3$4$5$6$7$8$9$10$11$12$13$14')


Тут широко используются незахватывающие скобки, чтобы оставить только захватывающие, для дальнейшей простоты второго аргумента в .replace(). (Подсказка-лайфхак: такие строки лучше всего читать в редакторе, имеющем выделение с подсветкой и выделение парных скобок, напр. от jetbrains.)


Для преобразования строки jsonComm в JSON достаточно этого выражения. Как показывают бенчмарки, это преобразование достаточно хорошо летает — время выполнения — десятки-сотни микросекунд на страницу (сильно зависит от сложности разбора). Хуже будет дело с академическим скриптом для вывода комментариев в JSON, когда в replace() понадобится функция.


Так, мы получили валидный JSON, решив первую часть задачи — прочитать jsonComm.


Затем, парсинг валидности оставшегося кода, как задумано, возлагается на стандартную JSON.parse(), после чего получаем структуру данных в JS. Следующая часть задачи — кое-что автоматически подредактировать в исходном тексте, оставив комментарии на местах.


Вставка некоторых обновлённых значений




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

Напомним ограничения, которые накладываем на правки.



  • в тексте jsonComm ищутся уникальные ключи (в кавычках). Копии ключей в комментариях игнорируются. Для одинаковых имён ключей из разных веток структуры — изменится первое и создастся некритическая ошибка в отчёте.

  • цепочки ключей не анализируются (для простоты и скорости поиска)

  • править пары, записанные не с начала строки — без проблем, потому что распознаватель ориентирован на скобки и запятые как маркеры пар. Но для удобства чтения и контроля лучше записывать изменяемые пары с начала строки.

  • удалить пару нельзя; самое большее — заменить на null или "". Как следствие, редактируемые ключи продолжают работать при любых автоматических изменениях, исчезнуть могут только при ручных.

  • изменяются только примитивы; массивы и структуры остаются на месте. Попытка изменить структуру приводит к нефатальной ошибке (пишется в лог ошибок).

  • изменение (переименование) ключей возможно, хотя противоречит человеко-ориентированному подходу и может привести к нарушению цепочки автоматических изменений, которое будет сложно отлаживать. Этим механизмом, возможно, удобно менять значения местами (перестановкой не значений, а ключей).


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


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


Изменение значений выполняется функцией jsonComm.change(h), где h — одноранговый набор пар «ключ»-«новое значение». (В крайнем случае — «ключ»- {«новый ключ»:«новое значение»}.)


Что интересно, для .change() файл (строка) не обязан быть приводимым к JSON и к нему не обязательно пытаться применять .unComment(). Это может быть JS-файл, который сначала выполнится (например, только для того, чтобы прочитать из него текущие значения настроек вместо чтения JSON), а затем к нему применится модификация значений. Т.е. .change() — это тоже достаточно автономная функция в сборке.


Академические задачи: смена формата файла




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

● получить комментарии в JSON (функция преобразования — jsonComm.comm2json),

● работа с YAML,

● двусторонние преобразования «jsonComm — YAML».

● то же для «jsonComm — XML».


В силу их невостребованности, для последних поставлены функции-заглушки, и только первая (comm2json) сделана ради академического интереса, для ответа на вопрос — насколько медленнее это будет. Приходится делать replace, в котором захватить параметры комментариев через функцию, а затем символ за символом проверять комментарии и преобразовывать имеющиеся в допустимые для JSON строковые символы.


Краткий ответ — становится медленее в 30 раз и тоже сильно зависит от сложности разбора, количества комментариев. Тестовый пример уложился примерно в 1 миллисекунду, но реальность легко сделает жизнь сложнее. Зато мы получаем первый инструмент для «полностью валидного» последующего преобразования в другие форматы данных (Yaml, XML).


Результаты теста




Посмотрим, как на субноуте средней руки эти 3 функции справляются с небольшим контрольным jsonComm, имеющим всевозможные (конечно, не все) сложности для парсинга. На скриншотах — исходные данные, но в проекте можно найти код этих данных и провести тесты на своём компьютере и браузере. На Firefox 34 (jsonComm.unComment):




На Хроме в этом тесте — вдвое лучшие результаты.

Как выполняется парсинг комментариев (jsonComm.comm2json)? Здесь замена работает через replace(,function).





У Хрома здесь и далее — сопоставимые результаты. Это значит, что его специально оптимизировали на замены строк (.replace()) без функций. В любом случае, первый тест — очень быстро, этот — умеренно.

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


Как изменяются значения ключей (jsonComm.change)? Здесь форма и красивость результата — уже на первом месте, потому что предназначено для чтения конфигов людьми. Правила замены показаны в объекте jCommChanges.





Тут можно обратить внимание, что массивы и структуры не меняются по определению наших правил. Даже если написано «multiline1: {newKey:'newValue'}», изменяется только ключ, а запрос на изменение значения игнорируется.

Чем больше изменений требуется сделать на том же участке jsonComm, тем медленнее работает скрипт (что логично). Исходя из приведённых объёмов, можно оценить, какой будет скорость на больших JSON. В общем, скорость — достаточно хорошая, если даже для правок идёт речь о единицах миллисекунд.


Как упоминалось, первая функция с компилированным регекспом в несжатом виде занимает менее 1 КБ. Минифицированные первые 3 функции с выбрасыванием нереализованных остальных заглушек — 2.1 КБ (src/jsonComm.min.js).


Новые вклады в проект




Что хотелось бы увидеть в проекте от новых контрибьюторов?

1) Кроме академических разделов, есть элементы парсинга, которые не помешало бы оттачивать в коде, чтобы выделять комментарии точнее (как показывает тестовый вывод в jsonCommTest.htm под заголовком «jsonWithComm», выходная строка .comm2json() не очень совершенна). Впрочем, в JSON.stringify уже есть способы вывести строку красивее, как показывает следующая строка лога под заголовком «jsObjWithComm».


2) Интересно было бы сравнение скорости со скриптовым парсингом.


3) Не отмечаются ошибки неуникального парсинга. Не обрабатываются JSON в виде одного примитива.


4) Плагины для Grunt, Gulp,….


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


● Всё, что описано — работает здесь: jsonComm — проект (Github), описание проекта (англ.).

Json — стандарт, rfc-4627 о нём же.

● Вопрос "Как мне прокомментировать JSON?" на SO.

JSON.minify() (блог) и Github/

grunt-, gulp, broccoli-, strip-json-comments (Github)

JSON Comments (другой автор)

Предложения по совершенствованию JSON (англ., 2011)

JSON5 (перекликается с прежним)

Hjson, the Human JSON (Hjson keep my comments when updating a config file.)



Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.



This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.