barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

пятница, 11 сентября 2015 г.

AvastVBoxSVC.exe и самопроизвольный выход Windows из ждущего режима

Снова к вопросу о самопроизвольном выходе винды и ждущего режима. Вывод "powercfg -lastwake" указал на некий AvastVBoxSVC.exe, что очевидно является частью антивируса avast! Для того, чтобы этот exe-шник перестал будить компьютер, нужно зайти в Панель управления -> Программы и компоненты, найти там аваст, нажать "Изменить", и удалить "Безопасные виртуальные машины" (если, конечно, этот компонента аваста Вам реально не нужен).

четверг, 10 сентября 2015 г.

YouTube Data API v3: ошибка "YouTubeSignUpRequired" при попытке загрузки видео

Проблема

Пытаюсь загрузить видео на Youtube с использованием YouTube Data API v3 (пока что просто с помощью curl), получаю ответ:
< HTTP/1.1 401 Unauthorized
< Vary: X-Origin
< WWW-Authenticate: Bearer realm="https://accounts.google.com/", error=invalid_token
< Content-Type: application/json; charset=UTF-8
< Date: Thu, 10 Sep 2015 16:57:36 GMT
< Expires: Thu, 10 Sep 2015 16:57:36 GMT
< Cache-Control: private, max-age=0
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Alternate-Protocol: 443:quic,p=1
< Alt-Svc: quic=":443"; p="1"; ma=604800
< Accept-Ranges: none
< Vary: Origin,Accept-Encoding
< Transfer-Encoding: chunked
<
{
 "error": {
  "errors": [
   {
    "domain": "youtube.header",
    "reason": "youtubeSignupRequired",
    "message": "Unauthorized",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Unauthorized"
 }
}
При этом с тем же самым токеном другие операции (получение списка подписок, получение списка видео и пр.) работают без проблем, т.е. проблема явно не в токене. 

Решение

У пользователя, которому я хочу загрузить новое видео, еще не создан свой канал. Идем на Youtube через браузер, заходим в "Мой канал", Youtube предлагает создать канал. Соглашаемся. Пробуем еще раз загрузить видео через Data API - ошибка ушла.

среда, 9 сентября 2015 г.

JCP + ruToken: ошибка "java.io.IOException: Can't connect to Aktiv Co. ruToken 0"

Проблема

Используется JCP + ruToken для вычисления ЭЦП. При попытке получить ключ с токена падает ошибка:
Caused by: java.security.UnrecoverableKeyException: Can't connect to Aktiv Co. ruToken 0
at ru.CryptoPro.JCP.KeyStore.s.e(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.engineGetKey(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.JCPKeyStore.engineGetKey(Unknown Source)
at java.security.KeyStore.getKey(KeyStore.java:792)
...
Caused by: java.io.IOException: Can't connect to Aktiv Co. ruToken 0
at rtjlib.JCP.RutokenReader.lock(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.j.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.a(Unknown Source)
Решение

Текст ошибки не особо содержателен, и по нему совершенно неочевидно, в чем именно проблема. Из того же JCP-шного ControlPane я великолепно вижу Aktiv Co. ruToken 0, включая ключ и сертификат на нем.
Декомпилируем rtjlib.JCP.RutokenReader (rtjlib.jar в jre/lib/ext того JDK, который используется для подписывания). Там IOException с таким текстом кидается в 2 местах, и если в одном он кидается просто в коде после неудачного коннекта, то вот во втором применен замечательный подход "проглатывания исключения":
try
    {
      arrayOfByte = nativeWinJavaReader.getAtr(str, "T=0|T=1");
    }
    catch (Exception localException1)
    {
      throw new IOException("Can't connect to " + str);
    }
Добавляем в бросаемое исключение исходный localException1:
    try
    {
      arrayOfByte = nativeWinJavaReader.getAtr(str, "T=0|T=1");
    }
    catch (Exception localException1)
    {
      throw new IOException("Can't connect to " + str, localException1);
    }
Перекомпилируем класс RutokenReader, подкладываем в целевой JDK. Получаем более развернутую ошибку:
Caused by: java.io.IOException: Can't connect to Aktiv Co. ruToken 0
at rtjlib.JCP.RutokenReader.lock(RutokenReader.java:38)
at ru.CryptoPro.JCP.KeyStore.j.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.a(Unknown Source)
... 25 more
Caused by: java.lang.Exception: Establish context failed with 0x8010001d
at rtjlib.nativeAPI.SCardEstablishContext(Native Method)
at rtjlib.readerImpl.nativeWinJavaReader.getAtr(Unknown Source)
at rtjlib.JCP.RutokenReader.lock(RutokenReader.java:34)
... 28 more
Гуглим код 0x8010001d, узнаем, что расшифровывается он как "SCARD_E_NO_SERVICE - "The Smart card resource manager is not running." (http://blogs.msdn.com/b/alejacma/archive/2011/05/19/scardestablishcontext-fails-with-scard-e-no-service-error.aspx). Гугл же подсказывает и возможную причину: ошибка может быть вызвана нехваткой прав к событию "Global\Microsoft Smart Card Resource Manager Started". На это событие есть права только у интерактивных пользователей, SYSTEM и LOCAL SERVICE. В моем же случае ошибка падала в службе, запускающейся из-под обычного пользователя (но т.к. вход не интерактивный - прав не хватало). Запустили целевую программу в интерактивном режиме (из командной строки) вместо запуска в качестве службы - ошибка ушла. Пока такое решение устроило.

КриптоПРО JCP XMLDSig: java.lang.ClassCastException: content[0] is not a valid X509Data type

При попытки подписывания XML-документа с помощью КриптоПРО JCP падает ошибка:
java.lang.ClassCastException: content[0] is not a valid X509Data type
at ru.CryptoPro.JCPxml.dsig.internal.dom.DOMX509Data.<init>(DOMX509Data.java:68)
at ru.CryptoPro.JCPxml.dsig.internal.dom.DOMKeyInfoFactory.newX509Data(DOMKeyInfoFactory.java:88)
...
Причина - в моем случае был неверно указан keyAlias.

понедельник, 7 сентября 2015 г.

Maven: включение в OSGI-бандл распакованных зависимостей

Задача

Распаковать в собираемый OSGI-бандл некоторые зависимости.

Решение

У maven-bundle-plugin есть инструкция "Embed-Dependency", однако она включает указанные зависимости не распаковывая, т.е. кладет jar-ник внутрь jar-ника. Поэтому приходится использовать комбинацию плагина maven-dependency-plugin и инструкцию "Include-Resource" плагина maven-bundle-plugin:
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
          <execution>
            <id>unpack-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <includeArtifactIds>saaj-impl,stax-ex,stax-api,mimepull</includeArtifactIds>
              <excludes>META-INF/**</excludes>
              <outputDirectory>${project.build.directory}/depsToPackIntoBundle</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.5.4</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>**</Bundle-SymbolicName>
            <Bundle-Name>***</Bundle-Name>
            <Export-Package>***</Export-Package>
            <Fragment-Host>***</Fragment-Host>
            <Import-Package>***</Import-Package>
            <Private-Package>***</Private-Package>
            <Include-Resource>${project.build.directory}/depsToPackIntoBundle</Include-Resource>
          </instructions>        
        </configuration>
      </plugin>
В данном примере зависимости saaj-impl,stax-ex,stax-api,mimepul будут запакованы в OSGI-бандл, за исключением их директорий META-INF.

Настройки log4j для отладки формирования и валидации XMLDSig средствами КриптоПро JCP

log4j.logger.org.jcp.xml.dsig.internal=DEBUG
log4j.logger.com.sun.org.apache.xml.internal.security=DEBUG
log4j.logger.ru.CryptoPro.JCPxml.dsig.internal=DEBUG
log4j.logger.ru.CryptoPro.JCPxml.dsig.internal.dom=DEBUG
log4j.logger.ru.CryptoPro.JCP=DEBUG

Windows: как узнать причину выхода компьютера из ждущего режима

Столкнулся с достаточно раздражающей проблемой: домашний комп самопроизвольно выходит из ждущего режима. Встал вопрос: кто именно в этом виноват? И тут на помощь приходит powercfg:
powercfg -lastwake
покажет, кто разбудил ПК.