Privet — это API локального обнаружения облачных устройств, используемый облачными службами. Этот документ состоит из следующих разделов:
- Введение : введение в Privet
- Обнаружение : локальные механизмы обнаружения
- Объявления : объявления о местных открытиях
- API : API-интерфейсы Privet для обычных облачных устройств.
- API принтера : частные API, используемые принтерами.
- Приложение : дополнительные схемы
1. Введение
Подключенные к облаку устройства имеют много преимуществ. Они могут использовать онлайн-сервисы преобразования, размещать очереди заданий, когда устройство находится в автономном режиме, и быть доступными из любой точки мира. Однако при наличии многих облачных устройств, доступных данному пользователю, нам необходимо предоставить метод для поиска ближайшего устройства на основе местоположения. Цель протокола Privet — связать гибкость облачных устройств с подходящим механизмом локального обнаружения, чтобы устройства было легко обнаруживать в новых средах.
Цели этого протокола:- сделать облачные устройства доступными для локального обнаружения
- зарегистрировать облачные устройства в облачном сервисе
- связать зарегистрированные устройства с их облачным представлением
- включить автономный функционал
- упростить реализацию, чтобы ее могли использовать небольшие устройства
Протокол Privet состоит из двух основных частей: обнаружения и API. Discovery используется для поиска устройства в локальной сети, а API — для получения информации об устройстве и выполнения некоторых действий. В этом документе под устройством понимается подключенное к облаку устройство, реализующее протокол Privet.
2. Открытие
Discovery — это протокол на основе Zeroconf (mDNS + DNS-SD). Устройство ДОЛЖНО реализовать локальную адресацию IPv4. Устройство ДОЛЖНО соответствовать спецификациям mDNS и DNS-SD.
- http://www.rfc-editor.org/rfc/rfc3927.txt (IPv4 Link-local)
- http://www.rfc-editor.org/rfc/rfc4862.txt (IPv6 Link-local)
- http://www.rfc-editor.org/rfc/rfc6762.txt (mDNS)
- http://www.rfc-editor.org/rfc/rfc6763.txt (DNS-SD)
Устройство ДОЛЖНО выполнять разрешение конфликтов имен в соответствии с приведенными выше спецификациями.
2.1. Тип Обслуживания
Обнаружение служб DNS использует следующий формат для типов служб: _applicationprotocol._transportprotocol . В случае протокола Privet тип сервиса для DNS-SD должен быть: _privet._tcp
Устройство также может реализовывать другие типы услуг. Рекомендуется использовать одно и то же имя экземпляра службы для всех типов служб, реализуемых устройством. Например: принтер может реализовать службы «Принтер XYZ._privet._tcp» и «Принтер XYZ._printer._tcp». Это упростит настройку для пользователя. Однако клиенты Privet будут искать только «_privet._tcp».
В дополнение к основному типу службы устройство ДОЛЖНО объявлять записи PTR для соответствующих подтипов (см. спецификацию DNS-SD: «7.1. Выборочное перечисление экземпляров (подтипы)»). Формат должен быть следующим: _<подтип>._sub._privet._tcp
В настоящее время поддерживается только один подтип устройства: принтер . Таким образом, все принтеры ДОЛЖНЫ объявлять две записи PTR:
- _privet._tcp.local.
- _printer._sub._privet._tcp.local.
2.2. TXT-запись
Обнаружение службы DNS определяет поля для добавления дополнительной информации о службе в записи TXT. Запись TXT состоит из пар ключ/значение. Каждая пара ключ/значение начинается с байта длины, за которым следует до 255 байтов текста. Ключ — это текст перед первым символом «=», а значение — текст после первого символа «=» до конца. Спецификация допускает отсутствие значения в записи, в этом случае не будет символа «=» ИЛИ текста после символа «=». (См. спецификацию DNS-SD: «6.1. Общие правила формата для записей TXT DNS» для формата записи TXT DNS и «6.2. Размер записи TXT DNS-SD» для рекомендуемой длины).
Privet требует, чтобы устройство отправляло следующие пары ключ/значение в записи TXT. Строки ключ/значение нечувствительны к регистру, например, "CS=online" и "cs=ONLINE" совпадают. Информация в записи TXT ДОЛЖНА быть такой же, как доступная через /info API (см. раздел 4.1. API).
Рекомендуется, чтобы размер записи TXT не превышал 512 байт.
2.2.1. txtvers
Версия структуры TXT. txtvers ДОЛЖНА быть первой записью структуры TXT. В настоящее время поддерживается только версия 1.
txtvers=1
2.2.2. ты
Предоставляет удобочитаемое имя устройства. Например:
ty=Google Cloud Ready Printer Model XYZ
2.2.3. примечание (необязательно)
Предоставляет удобочитаемое имя устройства. Например:
note=1st floor lobby printer
Примечание. Это необязательный ключ, и его можно пропустить. Однако, если оно присутствует, пользователь ДОЛЖЕН иметь возможность изменить это значение. Это же описание ДОЛЖНО использоваться при регистрации устройства.
2.2.4. URL
URL-адрес сервера, к которому подключено это устройство (включая протокол). Например:
url=https://www.google.com/cloudprint
2.2.5. тип
Разделенный запятыми список подтипов устройств, поддерживаемых этим устройством. Формат: "тип=_подтип1,_подтип2". В настоящее время единственным поддерживаемым подтипом устройства является принтер .
type=printer
Каждый перечисленный подтип должен рекламироваться с использованием соответствующей записи PTR. Для каждого поддерживаемого подтипа службы должен быть один соответствующий элемент. Имя подтипа службы (<subtype>._sub._privet._tcp) здесь должно совпадать с типом устройства.
2.2.6. я бы
Идентификатор устройства. Если устройство еще не зарегистрировано, этот ключ должен присутствовать, но значение должно быть пустым. Например:
id=11111111-2222-3333-4444-555555555555 id=
2.2.7. cs
Указывает текущее состояние подключения устройства. В этой спецификации определены четыре возможных значения.
- «онлайн» означает, что устройство в данный момент подключено к облаку.
- «оффлайн» означает, что устройство доступно в локальной сети, но не может связаться с сервером.
- «подключение» означает, что устройство выполняет последовательность запуска и еще не полностью подключено к сети.
- «не настроен» означает, что доступ устройства в Интернет еще не настроен. Это значение в настоящее время не используется, но может быть полезно в будущих версиях спецификации.
- cs=онлайн
- cs=оффлайн
- cs=подключение
Если устройство было зарегистрировано в облаке, при запуске оно должно проверить подключение к серверу, чтобы определить состояние подключения (например, вызов облачного API для получения настроек устройства). Устройство может использовать состояние соединения своего канала уведомлений (например, XMPP), чтобы сообщить об этом значении. Незарегистрированные устройства при запуске могут пинговать домен, чтобы определить состояние своего подключения (например, пинговать www.google.com для устройств облачной печати).
3. Объявления
При запуске, завершении работы или изменении состояния устройство ДОЛЖНО выполнить шаг объявления, как описано в спецификации mDNS . Ему СЛЕДУЕТ отправить соответствующее объявление не менее двух раз с интервалом не менее одной секунды между ними.
3.1. Запускать
При запуске устройства оно ДОЛЖНО выполнять шаги проверки и объявления, как описано в спецификации mDNS. В этом случае должны быть отправлены записи SRV, PTR и TXT. По возможности рекомендуется сгруппировать все записи в один ответ DNS. В противном случае рекомендуется следующий порядок: записи SRV, PTR, TXT.
3.2. Неисправность
При выключении устройства ему СЛЕДУЕТ попытаться уведомить об этом все заинтересованные стороны, отправив «прощальный пакет» с TTL = 0 (как описано в документации mDNS).
3.3. Обновлять
В случае изменения какой-либо информации, описанной в TXT, устройство ДОЛЖНО отправить уведомление об обновлении. В этом случае достаточно отправить только новую запись TXT. Например, после того, как устройство зарегистрировано, оно ДОЛЖНО отправить уведомление об обновлении, включая новый идентификатор устройства.
4. API
После обнаружения облачного устройства связь клиента с устройством включается непосредственно через локальную сеть. Все API основаны на HTTP 1.1. Форматы данных основаны на JSON. Запросы API могут быть запросами GET или POST.
Каждый запрос ДОЛЖЕН содержать допустимый заголовок « X-Privet-Token ». ЕДИНСТВЕННЫЙ запрос, которому разрешено иметь пустой заголовок «X-Privet-Token», — это запрос /privet/info (обратите внимание, что заголовок ДОЛЖЕН присутствовать). Если заголовок «X-Privet-Token» отсутствует, устройство ДОЛЖНО ответить следующей ошибкой HTTP 400:
HTTP/1.1 400 Missing X-Privet-Token header.
Если заголовок «X-Privet-Token» пуст или недействителен, устройство ДОЛЖНО ответить «недействительной ошибкой X-Privet-Token» (invalid_x_privet_token, подробности см. в разделе «Ошибки»). Единственным исключением является /info API. Дополнительные сведения о том, почему это делается и как должны генерироваться токены, см. в приложении A: XSSI и XSRF-атаки и их предотвращение.
Если запрошенный API не существует или не поддерживается, устройство ДОЛЖНО возвращать ошибку HTTP 404.
4.1. Доступность API
Перед раскрытием ЛЮБОГО API (включая /info API) устройство ДОЛЖНО связаться с сервером, чтобы проверить локальные настройки . Локальные настройки ДОЛЖНЫ сохраняться между перезапусками. Если сервер недоступен, следует использовать последние известные локальные настройки. Если устройство еще не зарегистрировано, оно должно соответствовать настройкам по умолчанию.
Устройства Cloud Print ДОЛЖНЫ выполнить описанные ниже действия для регистрации, получения и обновления локальных настроек.
4.1.1. Регистрация
Когда устройство регистрируется, оно ДОЛЖНО указать параметр «local_settings» следующим образом:
{ "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 } }Можно установить следующие параметры:
Имя значения | Тип значения | Описание |
---|---|---|
local_discovery | логический | Указывает, разрешена ли функция локального обнаружения. Если установлено значение «false», все локальные API (включая /info) и обнаружение DNS-SD должны быть отключены. По умолчанию новые регистрируемые устройства должны пройти «true». |
access_token_enabled | логическое значение (необязательно) | Указывает, следует ли предоставлять /accesstoken API в локальной сети. По умолчанию должно быть "true". |
принтер/local_printing_enabled | логическое значение (необязательно) | Указывает, должны ли функции локальной печати (/printer/createjob, /printer/submitdoc, /printer/jobstate) отображаться в локальной сети. По умолчанию должно быть "true". |
принтер/conversion_printing_enabled | логическое значение (необязательно) | Указывает, может ли локальная печать отправлять задание на сервер для преобразования. Имеет смысл только при включенной локальной печати. |
xmpp_timeout_value | интервал (необязательно) | Указывает количество секунд между эхо-запросами канала XMPP. По умолчанию ДОЛЖНО быть 300 (5 минут) или больше. |
Важно: Отсутствие какого-либо дополнительного значения указывает на то, что соответствующая функциональность полностью не поддерживается устройством.
4.1.2. Запускать
При запуске устройства оно должно связаться с сервером, чтобы проверить, какие API доступны для доступа в локальной сети. Для принтеров, подключенных к Cloud Print, они должны вызывать:
/cloudprint/printer?printerid=<printer_id>или
/cloudprint/list
/cloudprint/printer предпочтительнее /cloudprint/list, но оба варианта будут работать.
Этот API возвращает текущие параметры устройства, включая настройки для локального API. Ответ от сервера будет иметь следующий формат:
"local_settings": { "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 }, "pending": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": false, "printer/conversion_printing_enabled": false, "xmpp_timeout_value": 500 } }
"текущий" объект указывает на настройки, которые действуют в данный момент.
объект «ожидание» указывает на параметры, которые должны быть применены к устройству (этот объект может отсутствовать).
Как только устройство увидит «ожидающие» настройки, оно ДОЛЖНО обновить свое состояние (см. ниже).
4.1.3. Обновлять
Если требуется обновление настроек, на устройство будет отправлено уведомление XMPP. Уведомление будет в следующем формате:
<device_id>/update_settings
Получив такое уведомление, устройство ДОЛЖНО запросить у сервера последние настройки. Устройства Cloud Print ДОЛЖНЫ использовать:
/cloudprint/printer?printerid=<printer_id>
Как только устройство увидит раздел «ожидание» в результате использования /cloudprint/printer API (при запуске или из-за уведомления), оно ДОЛЖНО обновить свое внутреннее состояние, чтобы запомнить новые настройки. Он ДОЛЖЕН вызывать API сервера для подтверждения новых настроек. Для облачных принтеров устройство ДОЛЖНО вызывать /cloudprint/update API и использовать параметр «local_settings», как при регистрации.
При повторном подключении к каналу XMPP устройство ДОЛЖНО вызвать /cloudprint/printer API, чтобы проверить, не изменились ли локальные настройки с момента последнего раза.
4.1.3.1. Ожидание локальных настроек
Параметр «local_settings», который устройство использует для вызова API сервера, НЕ ДОЛЖЕН содержать раздел «ожидание».
4.1.3.2. Локальные настройки Текущие
ТОЛЬКО устройство может изменить «текущий» раздел «local_settings». Все остальные изменят «ожидающий» раздел и будут ждать, пока изменения не будут распространены на «текущий» раздел устройством.
4.1.4. Не в сети
Если невозможно связаться с сервером во время запуска, после уведомления устройство ДОЛЖНО использовать последние известные локальные настройки.
4.1.5. Удаление устройства из службы
Если устройство было удалено из службы (например, GCP), на устройство будет отправлено уведомление XMPP. Уведомление будет в следующем формате:
<device_id>/delete
Получив такое уведомление, устройство ДОЛЖНО обратиться к серверу для проверки своего состояния. Устройства Cloud Print ДОЛЖНЫ использовать:
/cloudprint/printer?printerid=<printer_id>
Устройство ДОЛЖНО получить успешный HTTP-ответ с success=false и без описания устройства/принтера. Это означает, что устройство было удалено с сервера, и устройство ДОЛЖНО стереть свои учетные данные и перейти в режим заводских настроек по умолчанию.
В ЛЮБОЙ раз, когда устройство получает ответ о том, что оно было удалено в результате использования /cloudprint/printer API (запуск, уведомление об обновлении настроек, ежедневная проверка связи), оно ДОЛЖНО удалить свои учетные данные и перейти в режим по умолчанию.
4.2. /privet/информационный API
Информационный API является ОБЯЗАТЕЛЬНЫМ и ДОЛЖЕН быть реализован на каждом устройстве. Это HTTP-запрос GET для URL-адреса «/privet/info»: GET /privet/info HTTP/1.1.
Информационный API возвращает основную информацию об устройстве и функциях, которые оно поддерживает. Этот API ДОЛЖЕН никогда не изменять статус устройства или выполнять какие-либо действия, поскольку он уязвим для XSRF-атак. Это ЕДИНСТВЕННЫЙ API, которому разрешено иметь пустой заголовок «X-Privet-Token». Клиенты должны вызывать /privet/info API с заголовком «X-Privet-Token», установленным на X-Privet-Token: «»
Информационный API ДОЛЖЕН возвращать данные, согласующиеся с данными, доступными в записи TXT во время обнаружения.
4.2.1. Вход
/privet/info API не имеет входных параметров.
4.2.2. Возвращаться
/privet/info API возвращает основную информацию об устройстве и поддерживаемых функциях.
Столбец TXT указывает на соответствующее поле в записи TXT DNS-SD.
Имя значения | Тип значения | Описание | ТЕКСТ |
---|---|---|---|
версия | нить | Самая высокая версия (major.minor) поддерживаемого API, в настоящее время 1.0 | |
имя | нить | Удобочитаемое имя устройства. | ты |
описание | нить | (необязательно) Описание устройства. ДОЛЖЕН быть изменен пользователем. | примечание |
URL | нить | URL-адрес сервера, с которым разговаривает это устройство. URL-адрес ДОЛЖЕН включать спецификацию протокола, например: https://www.google.com/cloudprint. | URL |
тип | список строк | Список поддерживаемых типов устройств. | тип |
я бы | нить | Идентификатор устройства, пусто, если устройство еще не зарегистрировано. | я бы |
устройство_состояние | нить | Состояние устройства. неактивный означает, что устройство готово обработка означает, что устройство занято и функциональность может быть ограничена в течение некоторого времени остановлен означает, что устройство не работает и требуется вмешательство пользователя. | |
connection_state | нить | Состояние подключения к серверу (base_url) онлайн - подключение доступно офлайн - нет связи подключение - выполнение шагов запуска not-configured — соединение еще не настроено Зарегистрированное устройство может сообщать о своем состоянии соединения на основе состояния канала уведомления (например, состояние соединения XMPP). | cs |
производитель | нить | Название производителя устройства | |
модель | нить | Модель устройства | |
серийный номер | нить | Уникальный идентификатор устройства. В этой спецификации это ДОЛЖЕН быть UUID. (спецификация GCP 1.1) (необязательно) Мы настоятельно рекомендуем везде использовать один и тот же идентификатор серийного номера, чтобы разные клиенты могли идентифицировать одно и то же устройство. Например, принтеры, реализующие IPP, могут использовать этот идентификатор серийного номера в поле «printer-device-id». | |
прошивка | нить | Версия прошивки устройства | |
время безотказной работы | инт | Количество секунд с момента загрузки устройства. | |
setup_url | нить | (необязательно) URL-адрес (включая протокол) страницы с инструкциями по установке | |
support_url | нить | (необязательно) URL (включая протокол) страницы с поддержкой, часто задаваемые вопросы | |
update_url | нить | (необязательно) URL (включая протокол) страницы с инструкциями по обновлению прошивки | |
x-privet-токен | нить | Значение заголовка X-Privet-Token , которое необходимо передать всем API для предотвращения атак XSSI и XSRF. См. 6.1. для деталей. | |
API | описание API | Список поддерживаемых API (описан ниже) | |
семантическое_состояние | JSON | (необязательно) Семантическое состояние устройства в формате CloudDeviceState . |
api — это список JSON, содержащий список API, доступных через локальную сеть. Обратите внимание, что не все API могут быть доступны одновременно в локальной сети. Например, новое подключенное устройство должно поддерживать только API /register:
"api": [ "/privet/register", ]После завершения регистрации устройство ДОЛЖНО прекратить поддержку /register API. Устройство также должно связаться со службой, чтобы указать, какие API-интерфейсы могут быть доступны через локальную сеть. Например:
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
В настоящее время доступны следующие API:
- /privet/register — API для регистрации устройств по локальной сети. (подробности см. в /privet/register API). Этот API ДОЛЖЕН быть скрыт после успешной регистрации устройства в облаке.
- /privet/accesstoken — API для запроса токена доступа с устройства (подробности см. в /privet/accesstoken API).
- /privet/capabilities — API для получения возможностей устройства (подробности см. в /privet/capabilities API).
- /privet/printer/* — API, относящийся к типу устройства «принтер», подробности см. в API конкретных принтеров.
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "idle", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ] }Вот пример ответа /privet/info для принтера, у которого закончились чернила (обратите внимание на поле semantic_state):
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "stopped", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ], "semantic_state": { "version": "1.0", "printer": { "state": "STOPPED", "marker_state": { "item": [ { "vendor_id": "ink", "state": "EXHAUSTED", "level_percent": 0 } ] } } } }
4.2.3. Ошибки
/privet/info API должен возвращать ошибку, ТОЛЬКО если отсутствует заголовок X-Privet-Token . Это ДОЛЖНА быть ошибка HTTP 400:
HTTP/1.1 400 Missing X-Privet-Token header.
4.3. /privet/регистрировать API
/privet/register API является НЕОБЯЗАТЕЛЬНЫМ. Это HTTP POST-запрос. /privet/register API ДОЛЖЕН проверять допустимый заголовок X-Privet-Token . Устройство ДОЛЖНО внедрить этот API в URL-адрес «/privet/register»:
POST /privet/register?action=start&user=user@domain.com HTTP/1.1 POST /privet/register?action=complete&user=user@domain.com HTTP/1.1
Устройство должно предоставлять /privet/register API ТОЛЬКО тогда, когда оно позволяет анонимную регистрацию в данный момент. Например:
- Когда устройство включено (или после нажатия специальной кнопки на устройстве) и еще не зарегистрировано, оно должно открыть API /privet/register, чтобы пользователь из локальной сети мог запросить принтер.
- После завершения регистрации устройство должно перестать предоставлять доступ к /privet/register API, чтобы другой пользователь в локальной сети не смог вернуть устройство.
- Некоторые устройства могут иметь разные способы регистрации устройств и вообще не должны предоставлять API /privet/register (например, коннектор Chrome Cloud Print).
Процесс регистрации состоит из 3 шагов (см. анонимную регистрацию для Cloud Print).
- Инициировать процесс анонимной регистрации.
- Клиент инициирует этот процесс, вызывая API /privet/register. В это время устройство может ожидать подтверждения пользователя.
- Получить токен претензии.
Клиент опрашивает, когда устройство готово к работе. Когда устройство готово, оно отправляет запрос на сервер для получения токена регистрации и URL-адреса регистрации. Полученный токен и URL ДОЛЖНЫ быть возвращены клиенту. Если на этом этапе устройство получает еще один вызов для инициализации регистрации, оно должно:
- Если это тот же пользователь, который начал регистрацию - удалите все предыдущие данные (если они были) и начните новый процесс регистрации.
- Если это другой пользователь - вернуть ошибку device_busy и тайм-аут 30 секунд.
Завершите процесс регистрации.
После того, как клиент заявил права на устройство, клиент должен уведомить устройство о завершении регистрации. После завершения процесса регистрации устройство должно отправить уведомление об обновлении, включая вновь полученный идентификатор устройства.
Примечание. Когда устройство обрабатывает вызов API /privet/register, никакие другие вызовы API /privet/register не могут обрабатываться одновременно. Устройство ДОЛЖНО возвращать ошибку device_busy и 30-секундный тайм-аут.
НАСТОЯТЕЛЬНО рекомендуется подтверждение пользователя для регистрации на устройстве. Если это реализовано, устройство ДОЛЖНО ждать подтверждения пользователя ПОСЛЕ того, как оно получит вызов API /privet/register?action=start. Клиент будет вызывать /privet/register?action=getClaimToken API, чтобы узнать, когда подтверждение пользователя завершено и доступен токен утверждения. Если пользователь отменяет регистрацию на устройстве (например, нажимает кнопку «Отмена»), ДОЛЖНА быть возвращена ошибка user_cancel. Если пользователь не подтвердил регистрацию в течение определенного периода времени, ДОЛЖНА быть возвращена ошибка подтверждения_timeout. См. раздел по умолчанию для более подробной информации.
4.3.1. Вход
/privet/register API имеет следующие входные параметры:Имя | Ценность |
---|---|
действие | Может быть одним из следующих: start - начать процесс регистрации getClaimToken — получить токен претензии для устройства Отменить - отменить процесс регистрации Complete - завершить процесс регистрации |
пользователь | Электронная почта пользователя, который будет заявлять права на это устройство. |
Устройство ДОЛЖНО проверить соответствие адреса электронной почты от всех действий (запуск, getClaimToken, отмена, завершение).
4.3.2. Возвращаться
/privet/register API возвращает следующие данные:Имя значения | Тип значения | Описание |
---|---|---|
действие | нить | То же действие, что и во входном параметре. |
пользователь | строка (необязательно) | Тот же пользователь, что и во входном параметре (может отсутствовать, если не указан во входных данных). |
жетон | строка (необязательно) | Токен регистрации (обязателен для ответа «getClaimToken», опущен для «начала», «завершения», «отмены»). |
претензия_url | строка (необязательно) | URL-адрес регистрации (обязателен для ответа «getClaimToken», опущен для «начала», «завершения», «отмены»). Для облачных принтеров это должен быть «complete_invite_url», полученный с сервера. |
автоматизированный_требование_url | строка (необязательно) | URL-адрес регистрации (обязателен для ответа «getClaimToken», опущен для «начала», «завершения», «отмены»). Для облачных принтеров это должен быть «automated_invite_url», полученный с сервера. |
идентификатор устройства | строка (необязательно) | Идентификатор нового устройства (опущен для ответа «запуск», обязателен для ответа «завершено»). |
Устройство ДОЛЖНО вернуть свой идентификатор устройства в ответ API /privet/info ТОЛЬКО после завершения регистрации.
Пример 1:
{ "action": "start", "user": "user@domain.com", }
Пример 2:
{ "action": "getClaimToken", "user": "user@domain.com", "token": "AAA111222333444555666777", "claim_url": "https://domain.com/SoMeUrL", }
Пример 3:
{ "action": "complete", "user": "user@domain.com", "device_id": "11111111-2222-3333-4444-555555555555", }
4.3.3. Ошибки
/privet/register API может возвращать следующие ошибки (подробности см. в разделе «Ошибки»):Ошибка | Описание |
---|---|
устройство_занято | Устройство занято и не может выполнить запрошенное действие. Повторите попытку после тайм-аута. |
pending_user_action | В ответ на «getClaimToken» эта ошибка указывает, что устройство все еще ожидает подтверждения пользователя, и запрос «getClaimToken» должен быть повторен после тайм-аута. |
user_cancel | Пользователь явным образом отменил процесс регистрации с устройства. |
подтверждение_тайм-аут | Время подтверждения пользователя истекло. |
недействительное_действие | Неверное действие называется. Например, если клиент вызвал action=complete перед вызовами action=start и action=getClaimToken. |
неверные_параметры | В запросе указаны неверные параметры. (Неизвестные параметры следует игнорировать для совместимости в будущем). Например, верните это, если клиент вызвал action=unknown или user=. |
device_config_error | Дата/время (или некоторые другие настройки) неверны на стороне устройства. Пользователю необходимо перейти (на внутренний веб-сайт устройства) и настроить параметры устройства. |
не в сети | В настоящее время устройство находится в автономном режиме и не может связаться с сервером. |
Ошибка сервера | Ошибка сервера в процессе регистрации. |
invalid_x_privet_token | X-Privet-Token недействителен или пуст в запросе. |
Устройство ДОЛЖНО перестать предоставлять /privet/register API после успешного завершения регистрации. Если устройство не предоставляет /privet/register API, оно ДОЛЖНО возвращать ошибку HTTP 404. Поэтому, если устройство уже зарегистрировано, вызов этого API ДОЛЖЕН возвращать 404. Если заголовок X-Privet-Token отсутствует, устройство ДОЛЖНО возвращать ошибку HTTP 400.
4.4. /privet/accesstoken API
API /privet/accesstoken является НЕОБЯЗАТЕЛЬНЫМ. Это запрос HTTP GET. /privet/accesstoken API ДОЛЖЕН проверять допустимый заголовок «X-Privet-Token». Устройство ДОЛЖНО реализовать этот API по URL-адресу «/privet/accesstoken»:GET /privet/accesstoken HTTP/1.1.
Когда устройство получает вызов API /accesstoken, оно должно вызвать сервер, чтобы получить токен доступа для данного пользователя и вернуть токен клиенту. Затем клиент будет использовать токен доступа для доступа к этому устройству через облако.
Устройства Cloud Print ДОЛЖНЫ вызывать следующий API:
/cloudprint/proximitytokenи передайте параметры «printerid=<printer_id>» и «user» из локального API. В случае успеха ответ сервера будет содержать следующий объект:
"proximity_token": { "user": "user@domain.com", "token": "AAA111222333444555666777", "expires_in": 600 }Устройства облачной печати ДОЛЖНЫ передавать значение объекта «proximity_token» в ответ на локальные вызовы API /privet/accesstoken. Более выгодно (на перспективу), если устройство может передавать ВСЕ параметры (включая те, которые не описаны в этой спецификации).
4.4.1. Вход
/privet/accesstoken API имеет следующие входные параметры:Имя | Ценность |
---|---|
пользователь | Электронная почта пользователя, который намеревался использовать этот токен доступа. Может быть пустым в запросе. |
4.4.2. Возвращаться
/privet/accesstoken API возвращает следующие данные:Имя значения | Тип значения | Описание |
---|---|---|
жетон | нить | Токен доступа, возвращаемый сервером |
пользователь | нить | Тот же пользователь, что и во входном параметре. |
истекает | инт | Количество секунд до истечения срока действия этого токена. Получено от сервера и передано в этом ответе. |
Пример:
{ "token": "AAA111222333444555666777", "user": "user@domain.com", "expires_in": 600 }
4.4.3. Ошибки
API /privet/accesstoken может возвращать следующие ошибки (подробности см. в разделе «Ошибки»):Ошибка | Описание |
---|---|
не в сети | Устройство в данный момент находится в автономном режиме и не может связаться с сервером. |
в доступе отказано | Недостаточно прав. В доступе отказано. Устройство должно возвращать эту ошибку, если запрос был явно отклонен сервером. |
неверные_параметры | В запросе указаны неверные параметры. (Неизвестные параметры следует игнорировать для совместимости в будущем). Например, если клиент вызвал /accesstoken?user= или /accesstoken. |
Ошибка сервера | Ошибка сервера. |
invalid_x_privet_token | X-Privet-Token недействителен или пуст в запросе. |
Если устройство не предоставляет /privet/accesstoken API, оно ДОЛЖНО возвращать ошибку HTTP 404. Если заголовок X-Privet-Token отсутствует, устройство ДОЛЖНО возвращать ошибку HTTP 400.
4.5. /privet/возможности API
/privet/capabilities API НЕОБЯЗАТЕЛЬНО. Это запрос HTTP GET. /privet/capabilities API ДОЛЖЕН проверять допустимый заголовок «X-Privet-Token». Устройство ДОЛЖНО внедрить этот API по URL-адресу «/privet/capabilities»:GET /privet/capabilities HTTP/1.1Когда устройство получает вызов API /capabilities, если устройство может, ему СЛЕДУЕТ связаться с сервером, чтобы получить обновленные возможности. Например, если принтер поддерживает отправку задания на печать (полученного локально) самому себе через службу облачной печати, он должен возвращать возможности, которые могла бы вернуть служба облачной печати. Cloud Print в этом случае может изменить исходные возможности принтера, добавив новые функции, которые он может выполнять перед отправкой задания на принтер. Самый распространенный случай — это список поддерживаемых типов документов. Если принтер находится в автономном режиме, он должен возвращать типы документов, которые он поддерживает. Однако, если принтер подключен к сети и зарегистрирован в Cloud Print, он ДОЛЖЕН возвращать «*/*» в качестве одного из поддерживаемых типов. В этом случае служба облачного принтера выполнит необходимое преобразование. Для автономной печати принтер ДОЛЖЕН поддерживать как минимум формат «image/pwg-raster».
4.5.1. Вход
/privet/capabilities API имеет следующие входные параметры:Имя | Ценность |
---|---|
не в сети | (необязательно) Может быть только "offline=1". В этом случае устройство должно возвращать возможности для автономного использования (если они отличаются от «онлайновых» возможностей). |
4.5.2. Возвращаться
/privet/capabilities API возвращает возможности устройства в формате JSON описания облачного устройства (CDD) (подробности см. в документе CDD). Принтеры как минимум ДОЛЖНЫ возвращать здесь список поддерживаемых типов. Например, готовый к работе в облаке принтер, который в данный момент подключен к сети, может вернуть что-то вроде этого (как минимум):{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" }, { "content_type": "*/*" } ] } }, а когда он отключится от сервера, он может вернуть:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }.
Примечание . Принтеры выражают приоритет поддерживаемого типа содержимого с помощью порядка. Например, в приведенных выше примерах принтер указывает, что он предпочитает данные «application/pdf», а не «image/pwg-raster» и «image/jpeg». Клиенты должны соблюдать приоритеты принтеров, если это возможно (подробности см. в документе CDD).
4.5.3. Ошибки
/privet/capabilities API может возвращать следующие ошибки (подробности см. в разделе «Ошибки»):Ошибка | Описание |
---|---|
invalid_x_privet_token | X-Privet-Token недействителен или пуст в запросе. |
Если устройство не предоставляет API /privet/capabilities, оно ДОЛЖНО возвращать ошибку HTTP 404. Если заголовок X-Privet-Token отсутствует, устройство ДОЛЖНО возвращать ошибку HTTP 400.
4.6. Ошибки
Ошибки возвращаются из вышеуказанных API в следующем формате:Имя значения | Тип значения | Описание |
---|---|---|
ошибка | нить | Тип ошибки (определяется для API) |
описание | строка (необязательно) | Человекочитаемое описание ошибки. |
server_api | строка (необязательно) | В случае ошибки сервера это поле содержит API-интерфейс сервера, который дал сбой. |
server_code | интервал (необязательно) | В случае ошибки сервера это поле содержит тот код ошибки, который вернул сервер. |
server_http_code | интервал (необязательно) | В случае ошибки сервера HTTP это поле содержит возвращенный сервером код ошибки HTTP. |
тайм-аут | интервал (необязательно) | Количество секунд ожидания клиента перед повторной попыткой (только для исправимых ошибок). Клиент ДОЛЖЕН рандомизировать фактическое время ожидания от этого значения до значения, равного + 20%. |
Все API ДОЛЖНЫ возвращать ошибку HTTP 400, если заголовок X-Privet-Token отсутствует.
HTTP/1.1 400 Отсутствует заголовок X-Privet-Token.
Пример 1:
{ "error": "server_error", "description": "Service unavailable", "server_api": "/submit", "server_http_code": 503 }
Пример 2:
{ "error": "printer_busy", "description": "Printer is currently printing other job", "timeout": 15 }
5. API принтера
Один из типов устройств, поддерживаемых этим протоколом, — тип принтера. Устройства, поддерживающие этот тип, МОГУТ реализовывать некоторые функции, специфичные для принтеров. В идеале печать на облачных принтерах будет проходить через сервер облачной печати:
![](https://developers.google.cn/cloud-print/images/privet_image07.jpg?authuser=3&hl=ru)
В некоторых случаях клиенту может потребоваться отправить документ локально. Это может понадобиться, если у клиента нет идентификатора Google или он не может связаться с сервером облачного принтера. В таком случае задание на печать будет отправлено локально на принтер. Принтер, в свою очередь, будет использовать службу облачной печати для постановки в очередь и преобразования заданий. Принтер повторно отправит задание, отправленное локально, в службу облачной печати, а затем запросит его, поскольку оно было отправлено через облако. Этот процесс обеспечит гибкое взаимодействие с пользователем с точки зрения обслуживания (преобразования) и управления/отслеживания заданий печати.
![](https://developers.google.cn/cloud-print/images/privet_image08.jpg?authuser=3&hl=ru)
Поскольку служба облачной печати реализует преобразование, принтер ДОЛЖЕН объявить о поддержке всех входных форматов («*/*») в списке поддерживаемых типов контента:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "*/*" } ] } }
В некоторых случаях требуется полностью автономное решение. Поскольку принтеры поддерживают ограниченное количество входных форматов, клиенту потребуется преобразовать документы в несколько исходно поддерживаемых форматов принтеров.
![](https://developers.google.cn/cloud-print/images/privet_image04.jpg?authuser=3&hl=ru)
Эта спецификация ТРЕБУЕТ, чтобы все принтеры поддерживали по крайней мере формат PWG Raster ("изображение/pwg-растр") для случая автономной печати. Принтер может поддерживать другие форматы (например, JPEG), и если клиент поддерживает его, он может отправлять документы в этом формате. Принтер ДОЛЖЕН предоставлять поддерживаемые типы через API /capabilities, например:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }Клиент может инициировать печать по локальной сети двумя способами.
Простая печать - клиент отправляет документ по локальной сети в /submitdoc API (без указания параметра job_id). Отправленный документ будет распечатан с использованием настроек билета печати по умолчанию, и статусы заданий печати не требуются. Если принтер поддерживает ТОЛЬКО этот тип печати, он ДОЛЖЕН объявлять ТОЛЬКО /submitdoc API в ответе /privet/info API.
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
Расширенная печать — клиент должен сначала создать задание на печать на принтере, вызвав API /privet/printer/createjob с действительным билетом задания CJT в запросе. Принтер ДОЛЖЕН сохранить билет печати в памяти и вернуть клиенту job_id. Затем клиент вызовет API /printer/submitdoc и укажет ранее полученный job_id . В это время принтер начнет печатать. Клиент будет опрашивать принтер о статусе задания на печать, вызывая API /privet/printer/jobstate .
В мультиклиентской среде нет гарантии, как будет вызываться этот API. Один клиент может вызывать /createjob между вызовами /createjob->/submitdoc другого клиента. Для устранения возможных взаимоблокировок и повышения удобства использования мы рекомендуем иметь на принтере небольшую очередь ожидающих заданий на печать (не менее 3-5):
- /createjob занимает первое доступное место в очереди.
- Время жизни задания (в очереди) не менее 5 минут.
- Если все места в очереди заняты, то самое старое непечатаемое задание будет удалено и туда будет помещено новое.
- If there is a print job currently printing on the device (simple or advanced printing), /submitdoc should return status busy and propose a timeout to retry this print job.
- If /submitdoc refers to a job that has been removed from the queue (due to replacement or timeout), the printer should return an error invalid_print_job and the client will retry the process from the /createjob step. The client MUST wait for a random timeout period of up to 5 seconds before retrying.
If memory constraints prevent storing multiple pending jobs on the device, it is possible to have a queue of 1 print job long. It should still follow the same protocol as above. After a job has completed or failed with an error, the printer should store information about the job's status for at least 5 minutes. The queue size for storing completed job statuses should be at least 10. If there are more job statuses that need to be stored, the oldest one may be removed from the queue before the 5 minute timeout.
Note: For now clients will poll for job status. In the future, we may require the printer to send TXT DNS notification when ANY print job status has changed.
5.1. /privet/printer/createjob API
/privet/printer/createjob API is OPTIONAL (see Simple Printing above). It is an HTTP POST request. /privet/printer/createjob API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/createjob" url:
POST /privet/printer/createjob HTTP/1.1When receiving /privet/printer/createjob API call, the printer MUST create a new print job ID, store the received print ticket in the CJT format, and return print job id back to the client.
5.1.1. Input
/privet/printer/createjob API has no input parameters in URL. The request body should contain the print job ticket data in CJT format.5.1.2. Возвращаться
/privet/printer/createjob API returns the following data:Value name | Value type | Описание |
---|---|---|
job_id | string | ID of the newly created print job. |
expires_in | int | Number of seconds this print job is valid. |
Example:
{ "job_id": "123", "expires_in": 600 }
5.1.3. Errors
/privet/printer/createjob API may return the following errors (see Errors section for details):Error | Описание |
---|---|
invalid_ticket | Submitted print ticket is invalid. |
printer_busy | Printer is busy and can't currently process /createjob. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/createjob it MUST return HTTP 404 error. If X-Privet-Token header is missing, the device MUST return HTTP 400 error.
5.2. /privet/printer/submitdoc API
/privet/printer/submitdoc API is REQUIRED to implement printing over a local network (offline or repost to Cloud Print). It is an HTTP POST request. /privet/printer/submitdoc API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/submitdoc" url:POST /privet/printer/submitdoc HTTP/1.1When receiving the /privet/printer/submitdoc API call, the printer should start printing. If it is unable to begin printing, it MUST return the error printer_busy and a recommended timeout period for the client to wait before trying again.
If the printer is not able to hold all of the data in its internal buffer, it SHOULD use TCP mechanisms to slow down data transfer until it prints a portion of the document, making part of the buffer available again. (For example, the printer may set windowsize=0 on TCP layers, which will make the client wait.)
Submitting a document to the printer may take a significant amount of time. The client should be able to check the state of the printer and job (advanced printing) while printing is in progress. In order to do that, the printer MUST allow the client to call the /privet/info and /privet/printer/jobstate APIs while processing /privet/printer/submitdoc API calls. It is recommended for all clients to start a new thread to execute the /privet/printer/submitdoc API call, so that the main thread can use the /privet/info and /privet/printer/jobstate APIs to check printer and job states.
Note : Upon completion or abortion of the local print job, it is strongly recommended (and will be required in a future version of this spec) to report the final state of the job to the /cloudprint/submit interface for accounting and user experience purposes. The parameters "printerid", "title", "contentType" and "final_semantic_state" (in PrintJobState format) are required, and the parameters "tag" (repeated parameter) and "ticket" (the ticket of the job in CloudJobTicket format). Note that the provided PrintJobState must actually be final, ie its type must be DONE or ABORTED, and a cause must be provided in the case that it is ABORTED (see JobState for details). Also note that this use of the /cloudprint/submit interface to report local print jobs is not mentioned in its specification because that section is intended to describe the interface's primary use: submitting a print job with the document to print provided in the "content" parameter.
5.2.1. Input
/privet/printer/submitdoc API has the following input parameters:Имя | Value |
---|---|
job_id | (optional) Print job id. May be omitted for simple printing case (see above). Must match the one returned by the printer. |
user_name | (optional) Human readable user name. This is not definitive, and should only be used for print job annotations. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
client_name | (optional) Name of the client application making this request. For display purposes only. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
job_name | (optional) Name of the print job to be recorded. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
offline | (optional) Could only be "offline=1". In this case printer should only try printing offline (no re-post to Cloud Print server). |
Request body should contain a valid document for printing. "Content-Length" should include the correct length of the request. "Content-Type" header should be set to document MIME type and match one of the types in the CDD (unless CDD specifies "*/*").
Clients are HIGHLY recommended to provide a valid user name (or email), a client name and a job name with this request. Those fields are only used in UIs to improve user experience.
5.2.2. Возвращаться
/privet/printer/submitdoc API returns following data:Value name | Value type | Описание |
---|---|---|
job_id | string | ID of the newly created print job (simple printing) or job_id specified in the request (advanced printing). |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | Content-type of the submitted document. |
job_size | int 64 bit | Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
Example:
{ "job_id": "123", "expires_in": 500, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
5.2.3. Errors
/privet/printer/submitdoc API may return the following errors (see Errors section for details):Error | Описание |
---|---|
invalid_print_job | Invalid/expired job id is specified in the request. Retry after timeout. |
invalid_document_type | Document MIME-type is not supported by the printer. |
invalid_document | Submitted document is invalid. |
document_too_large | Document exceeds maximum size allowed. |
printer_busy | Printer is busy and can't currently process document. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility) |
user_cancel | User explicitly cancelled printing process from the device. |
server_error | Posting document to Cloud Print has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If the device is not exposing /privet/printer/submitdoc, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
Note : /privet/printer/submitdoc API may require special handling on printer side (because of the large payload attached). In some cases (depends on the printer HTTP server implementation and platform), printer may close socket BEFORE returning HTTP error. In other, printer may return 503 error (instead of Privet error). Printers SHOULD try as much as possible to return Privet. However, every client implementing Privet specification SHOULD be able to handle socket close (no HTTP error) and 503 HTTP error cases for /privet/printer/submitdoc API. In this case, client SHOULD handle it as a Privet "printer_busy" error with "timeout" set to 15 seconds. To avoid infinite retries, client may stop retrying after a reasonable number of attempts (for example, 3).
5.3. /privet/printer/jobstate API
/privet/printer/jobstate API is OPTIONAL (see Simple Printing above). It is an HTTP GET request. /privet/printer/jobstate API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/jobstate" url:GET /privet/printer/jobstate HTTP/1.1When receiving a /privet/printer/jobstate API call, a printer should return the status of the requested print job or invalid_print_job error.
5.3.1. Input
/privet/printer/jobstate API has following input parameters:Имя | Value |
---|---|
job_id | Print job ID to return status for. |
5.3.2. Возвращаться
/privet/printer/jobstate API returns the following data:Value name | Value type | Описание |
---|---|---|
job_id | string | Print job id there status information is for. |
state | string | draft - print job has been created on the device (no /privet/printer/submitdoc calls have been received yet). queued - print job has been received and queued, but printing has not started yet. in_progress - print job is in the progress of printing. stopped - print job has been paused, but can be restarted manually or automatically. done - print job is done. aborted - print job failed. |
description | string | (optional) Human readable description of the print job status. Should include additional information if state < is stopped or aborted . The semantic_state field usually provides better and more meaningful description to the client. |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | (optional) Content-type of the submitted document. |
job_size | int 64 bit | (optional) Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
server_job_id | string | (optional) ID of the job returned from the server (if job has been posted to Cloud Print service). Omitted for offline printing. |
semantic_state | JSON | (optional) Semantic state of the job in PrintJobState format. |
Example (printing by reporting through Cloud Print):
{ "job_id": "123", "state": "in_progress", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "server_job_id": "1111-2222-3333-4444" }
Example (offline printing error):
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
Example (print job aborted by the user):
{ "job_id": "123", "state": "aborted", "description": "User action", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"} }, "pages_printed": 7 } }
Example (print job stopped due to out of paper). Notice the reference to the device state. The client will need to call the /privet/info API to get more details about the device state:
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": "123456", "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "STOPPED", "device_state_cause": {"error_code": "INPUT_TRAY"} }, "pages_printed": 7 } }
5.3.3. Errors
/privet/printer/jobstate API may return the following errors (see Errors section for details):Error | Описание |
---|---|
invalid_print_job | Invalid/expired job ID is specified in the request. |
server_error | Getting print job status (for print jobs posted to Cloud Print) has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/jobstate, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
6. Appendix
6.1. Default behavior and settings
This section will explain the default behavior we expect from ALL Privet-compatible devices.- Out-of-the-box devices should support only /privet/info and /privet/register APIs. All other APIs (eg /privet/accesstoken, local printing) should be disabled.
- Registration requires physical interaction with a device.
- User MUST take a physical action on the device (eg, pressing a button) to confirm their access to the device.
- After the user takes the action noted above, the printer should send the /cloudprint/register request. It should not send this request until after the action is taken (see Sequence Diagram 1).
- If the device is processing a /privet/register request (for instance, waiting on the action above), it must reject all other /privet/register requests. The device MUST return the device_busy error in this case.
- The device should timeout any /register request that does not receive the physical action mentioned above within 60 seconds. The device MUST return the confirmation_timeout error in this case.
- Optional: Recommended but not required, the following may improve user experience:
- The printer might flash a light or its screen to indicate that the user needs to take an action to confirm registration.
- The printer might state on its screen that 'it is being registered to Google Cloud Print for user ' abc@def.com ' - press OK to continue', where abc@def.com is the user parameter from the /register API call. This would make it clearer to a user that:
- it is their registration request that they are confirming
- what is happening if s/he didn't trigger the request.
- In addition to a physical action to confirm from the printer (eg, 'Press the OK button'), a printer may also offer the user a button to cancel the request (eg, 'Press Cancel to reject'). This would allow users who did not trigger the registration request to cancel it before the 60 second timeout. The device MUST return the user_cancel error in this case.
- Ownership transfers:
- The device may be deleted explicitly from the Cloud service.
- If the device receives success, but no device description as a result of /cloudprint/printer (for GCP) call, it MUST revert to default (out-of-the-box) mode.
- If the device's credentials no longer work (explicitly because of "invalid credentials" response from the server), it MUST revert to default (out-of-the-box) mode.
- Local factory reset MUST clear device's credentials and set it to default state.
- Optional: The device may provide a menu item to clear credentials and put it into default mode.
- Devices supporting XMPP notifications MUST include the ability to ping the server. The ping timeout MUST be controllable from the server through "local_settings".
- The device may explicitly ping the server (/cloudprint/printer API for GCP, in addition to XMPP pings) no more often than once a day (24 hours) to make sure they are in sync. It is recommended to randomize the check window within 24-32 hour window.
- Optional: For Cloud Print devices, it is recommended but not required to have a manual way (button) to allow the user to initiate a check for new print jobs from the device. Some printers already have this.
- Optional. Enterprise printers may have an option to disable local discovery completely. In such case, the device MUST update these local settings on the server. New local settings MUST be empty (setting "local_discovery" to "false", means that it can be re-enabled from the GCP Service).
6.1.2 Default Registration Diagram
![](https://developers.google.cn/cloud-print/images/privet_image06.png?authuser=3&hl=ru)
6.2. XSSI and XSRF attacks and prevention
This section will explain the possibility of XSSI and XSRF attacks on the device and how to protect from them (including token generation techniques).More details are here: http://googleonlinesecurity.blogspot.com/2011/05/website-security-for-webmasters.html
Normally, XSSI and XSRF attacks are possible when a site is using cookie authentication mechanisms. While Google doesn't use cookies with their Cloud Print Service, such attacks are still possible. Local network access, by design, implicitly trusts requests.
6.2.1. XSSI
It is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and to try to call the Privet API using "src=<api name>" inside of a <script> tag:<script type="text/javascript" src="http://192.168.1.42:8080/privet/info"></script>Without protection, malicious websites would be able to execute API calls and access results.
To prevent this type of attack, ALL Privet API calls MUST require the "X-Privet-Token" header in the request. "src=<api>" script tags are not able to add headers, effectively guarding against this type of attack.
6.2.2. XSRF
http://en.wikipedia.org/wiki/Cross-site_request_forgeryIt is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and try to call Privet API using an <iframe>, forms, or some other cross-website loading mechanism. Attackers would not be able to access the results of the request, but if the request would perform an action (eg printing), they could trigger it.
To prevent this attack, we require the following protection:
- Leave /privet/info API open to XSRF
- /privet/info API MUST NOT perform any actions on the device
- Use /privet/info API to receive x-privet-token
- All other APIs MUST check for a valid x-privet-token in "X-Privet-Token" header.
- x-privet-token SHOULD be valid for only 24 hours.
Even if an attacker is able to execute the /privet/info API, they would not be able to read x-privet-token from the response and therefore would not be able to call any other API.
It is strongly recommended to generate the XSRF token using the following algorithm:
XSRF_token = base64( SHA1(device_secret + DELIMITER + issue_timecounter) + DELIMITER + issue_timecounter )
XSRF Token Generation Elements:
- DELIMITER is a special character, usually ':'
- issue_timecounter is a number of seconds since some event (epoch for timestamp) or device boot time (for CPU counters). issue_timecounter is constantly increasing when the device is up and running (see token verification below).
- SHA1 - hash function using SHA1 algorithm
- base64 - base64 encoding
- device_secret - secret specific to the device. Device secret MUST be updated on every restart.
Recommended ways to generate device secret:
- Generate a new UUID on every restart
- Generate a 64 bit random number on every restart
The device is not required to store all of the XSRF tokens it has issued. When the device needs to verify a XSRF token for validity, it should base64-decode the token. Get the issue_timecounter from the second half (cleartext), and try to produce SHA1 hash of device_secret + DELIMITER + issue_timecounter where issue_timecounter is from the token. If the newly generated SHA1 matches the one in the token, device must now check if the issue_timecounter is within the validity period from (24 hours) of the current time counter. To do so, device takes the current time counter (CPU counter for example) and subtracts issue_timecounter from it. The result MUST be the number of seconds since token issue.
Important: This is the recommended way to implement XSRF protection. Clients of the Privet specification shall not try to understand XSRF token, instead they shall treat is as a blackbox. Figure 6.2.3 illustrates a recommended way to implement the X-Privet-Token and verification of a typical request.
6.2.3 X-Privet Token Generation and Verification Sequence Diagram
![](https://developers.google.cn/cloud-print/images/privet_image03.png?authuser=3&hl=ru)
6.3. Workflow diagrams
This section will illustrate a workflow in different cases.6.3.1. Printer out of the box workflow
![](https://developers.google.cn/cloud-print/images/privet_image01.png?authuser=3&hl=ru)
6.3.2. Registered printer startup
![](https://developers.google.cn/cloud-print/images/privet_image02.png?authuser=3&hl=ru)
6.3.3 XMPP notifications handling workflow
![](https://developers.google.cn/cloud-print/images/privet_image05.png?authuser=3&hl=ru)
6.3.4. Check printer settings workflow
![](https://developers.google.cn/cloud-print/images/privet_image00.png?authuser=3&hl=ru)
Privet is a Cloud Device Local Discovery API used by cloud services. This document is organized into the following sections:
- Introduction : introduction to Privet
- Discovery : local discovery mechanisms
- Announcements : local discovery announcements
- API : Privet APIs for general cloud devices
- Printer API : Privet APIs used by printers
- Appendix : supplemental diagrams
1. Introduction
Cloud connected devices have many benefits. They can use online conversion services, host job queues while the device is offline, and be accessible from anywhere in the world. However, with many cloud devices accessible by a given user, we need to provide a method for finding the nearest device based on location. The purpose of the Privet protocol is to bind the flexibility of cloud devices with a suitable local discovery mechanism so that devices are easily discovered in new environments.
The goals of this protocol are:- make cloud devices locally discoverable
- register cloud devices with a cloud service
- associate registered devices with their cloud representation
- enable offline functionality
- simplify implementation so that small devices can utilize it
The Privet protocol consists of 2 main parts: discovery and API. Discovery is used to find the device on the local network, and the API is used to get information about the device and perform some actions. Throughout this document, the device refers to a cloud connected device implementing the Privet protocol.
2. Discovery
Discovery is a zeroconf based (mDNS + DNS-SD) protocol. The device MUST implement IPv4 Link-Local Addressing. The device MUST comply with the mDNS and DNS-SD specs.
- http://www.rfc-editor.org/rfc/rfc3927.txt (IPv4 Link-local)
- http://www.rfc-editor.org/rfc/rfc4862.txt (IPv6 Link-local)
- http://www.rfc-editor.org/rfc/rfc6762.txt (mDNS)
- http://www.rfc-editor.org/rfc/rfc6763.txt (DNS-SD)
The device MUST perform name conflict resolution according to the above specifications.
2.1. Service Type
DNS Service Discovery uses the following format for service types: _applicationprotocol._transportprotocol . In the case of the Privet protocol, the service type for DNS-SD should be: _privet._tcp
The device can implement other service types as well. It is advised to use the same service instance name for all service types implemented by the device. For example: a printer may implement "Printer XYZ._privet._tcp" and "Printer XYZ._printer._tcp" services. It will simplify setup for the user. However, Privet clients will look only for "_privet._tcp".
In addition to the main service type, the device MUST advertise the PTR records for its corresponding subtype(s) (see DNS-SD spec: "7.1. Selective Instance Enumeration (Subtypes)"). Format should be following: _<subtype>._sub._privet._tcp
Currently the only device subtype supported is printer . So, all printers MUST advertise two PTR records:
- _privet._tcp.local.
- _printer._sub._privet._tcp.local.
2.2. TXT record
The DNS Service Discovery defines fields to add optional information about a service in the TXT records. A TXT record consists of key/value pairs. Each key/value pair starts from the length byte followed by up to 255 bytes of text. The key is the text before the first '=' character and the value is the text after the first '=' character until the end. The specification allows for no value in the record, in such case the will be no '=' character OR no text after the '=' character. (See DNS-SD spec: "6.1. General Format Rules for DNS TXT Records" for the DNS TXT record format and "6.2. DNS-SD TXT Record Size" for the recommended length).
Privet requires the device to send the following key/value pairs in the TXT record. Key/Value strings are case-insensitive, for example "CS=online" and "cs=ONLINE" are the same. Information in the TXT record MUST be the same as accessible through /info API (see 4.1. API section).
It is recommended to keep TXT record size under 512 bytes.
2.2.1. txtvers
Version of the TXT structure. txtvers MUST be the first record of the TXT structure. Currently the only supported version is 1.
txtvers=1
2.2.2. ty
Provides a user-readable name of the device. For example:
ty=Google Cloud Ready Printer Model XYZ
2.2.3. note (optional)
Provides a user-readable name of the device. For example:
note=1st floor lobby printer
Note: This is an optional key and may be skipped. However, if present, user SHOULD be able to modify this value. The same description MUST be used when registering device.
2.2.4. url
Server URL this device is connected to (including protocol). For example:
url=https://www.google.com/cloudprint
2.2.5. type
Comma-separated list of device subtypes supported by this device. Format is: "type=_subtype1,_subtype2". Currently, the only supported device subtype is printer .
type=printer
Each subtype listed should be advertised using a corresponding PTR record. For each supported service subtype, there should be one corresponding item. Service subtype name (<subtype>._sub._privet._tcp) should be equal to device type here.
2.2.6. id
Device ID. If the device has not been registered yet, this key should be present, but value should be empty. For example:
id=11111111-2222-3333-4444-555555555555 id=
2.2.7. cs
Indicates the device's current connection state. Four possible values are defined in this spec.
- "online" indicates that the device is currently connected to the cloud.
- "offline" indicates that the device is available on the local network, but can't talk to the server.
- "connecting" indicates that the device is performing its startup sequence and is not fully online yet.
- "not-configured" indicates that the device's internet access has not been configured yet. This value is not currently used, but may be useful in future versions of the specification.
- cs=online
- cs=offline
- cs=connecting
If the device has been registered with a cloud, on startup it should check connectivity with a server to detect its connection state (for example, calling cloud API to get device settings). The device may use its notifications channel (eg XMPP) connection state to report this value. Unregistered devices on startup may ping a domain in order to detect their connection state (for example, ping www.google.com for cloud print devices).
3. Announcements
On device startup, shutdown or state change, the device MUST perform the announcement step as described in the mDNS specification. It SHOULD send the corresponding announcement at least twice with at least a one-second interval between them.
3.1. Startup
On device startup it MUST perform probing and announcing steps as described in the mDNS specification. SRV, PTR and TXT records should be sent in this case. It is recommended to group all records into one DNS response if possible. If not, the following order is recommended: SRV, PTR, TXT records.
3.2. Shutdown
On device shutdown it SHOULD try to notify all interested parties about it by sending a "goodbye packet" with TTL=0 (as described in mDNS documentation).
3.3. Update
In case of any information described in TXT has changed, the device MUST send an update announcement. It is enough to only send the new TXT record in this case. For example, after a device is registered, it MUST send an update announcement including the new device id.
4. API
After a cloud device has been discovered, client communication is enabled with the device directly over the local network. All APIs are HTTP 1.1 based. Data formats are JSON based. API requests may be GET or POST requests.
Each request MUST contain a valid " X-Privet-Token " header. The ONLY request allowed to have an empty "X-Privet-Token" header is the /privet/info request (note that the header MUST still be present). If the "X-Privet-Token" header is missing, the device MUST respond with the following HTTP 400 error:
HTTP/1.1 400 Missing X-Privet-Token header.
If "X-Privet-Token" header is empty or invalid, the device MUST respond with "invalid X-Privet-Token error" (invalid_x_privet_token, see Errors section for details). The only exception is the /info API. To see more info on why this is done and how tokens should be generated, see Appendix A: XSSI and XSRF attacks and prevention.
If a requested API does not exist or is not supported, the device MUST return an HTTP 404 error.
4.1. API availability
Before ANY API is exposed (including the /info API), the device MUST contact the server to check local settings . Local settings MUST be preserved between restarts. If the server is not available, the last known local settings should be used. If the device has not been registered yet, it should follow the default settings.
Cloud Print devices MUST follow the steps below to register, receive and update local settings.
4.1.1. Registration
When the device registers, it MUST specify the "local_settings" parameter, as follows:
{ "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 } }The following settings can be set:
Value Name | Value Type | Описание |
---|---|---|
local_discovery | boolean | Indicates if local discovery functionality is allowed. If "false", all local API (including /info) and DNS-SD discovery must be disabled. By default, newly registering devices should pass "true". |
access_token_enabled | boolean (optional) | Indicates if /accesstoken API should be exposed on the local network. By default should be "true". |
printer/local_printing_enabled | boolean (optional) | Indicates if local printing functionality (/printer/createjob, /printer/submitdoc, /printer/jobstate) should be exposed on the local network. By default should be "true". |
printer/conversion_printing_enabled | boolean (optional) | Indicates if local printing may send job to server for conversion. Only makes sense when local printing is enabled. |
xmpp_timeout_value | int (optional) | Indicates the number of seconds between XMPP channel pings. By default MUST be 300 (5 minutes) or more. |
Important: The lack of any optional value indicates that the corresponding functionality is completely unsupported by the device.
4.1.2. Startup
On device startup, it should contact the server to check what APIs are available to be exposed in the local network. For printers connected to Cloud Print, they should call:
/cloudprint/printer?printerid=<printer_id>or
/cloudprint/list
/cloudprint/printer is preferred over /cloudprint/list, but both will work.
This API returns current device parameters, including settings for local API. The reply from the server will have the following format:
"local_settings": { "current": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": true, "printer/conversion_printing_enabled": true, "xmpp_timeout_value": 300 }, "pending": { "local_discovery": true, "access_token_enabled": true, "printer/local_printing_enabled": false, "printer/conversion_printing_enabled": false, "xmpp_timeout_value": 500 } }
"current" object indicates settings that are in effect at the moment.
"pending" object indicates settings that should be applied to the device (this object may be missing).
Once the device sees "pending" settings, it MUST update its state (see below).
4.1.3. Update
If settings update is needed, an XMPP notification will be sent to the device. The notification will be in the following format:
<device_id>/update_settings
On receiving such a notification, the device MUST query the server to get the latest settings. Cloud Print devices MUST use:
/cloudprint/printer?printerid=<printer_id>
Once the device sees "pending" section as a result of the /cloudprint/printer API (at startup or due to the notification), it MUST update its internal state to remember the new settings. It MUST call the server API to confirm the new settings. For Cloud Printers, the device MUST call /cloudprint/update API and use "local_settings" parameter as during registration.
When re-connecting to XMPP channel, the device MUST call /cloudprint/printer API to check if local settings has been changed since the last time.
4.1.3.1. Local Settings Pending
"local_settings" parameter that device uses to call server API MUST NEVER contain "pending" section.
4.1.3.2. Local Settings Current
ONLY the device can change the "current" section of the "local_settings". Everybody else will change the "pending" section, and wait until changes get propagated to the "current" section by the device.
4.1.4. Offline
When unable to contact the server during startup, after notification, device MUST use last known local settings.
4.1.5. Deleting device from the service
If the device has been deleted from the service (GCP for example), an XMPP notification will be sent to the device. The notification will be in the following format:
<device_id>/delete
On receiving such a notification, the device MUST go to the server to check its state. Cloud Print devices MUST use:
/cloudprint/printer?printerid=<printer_id>
The device MUST receive a successful HTTP answer with success=false and no device/printer description. It means device has been removed from the server, and the device MUST erase its credentials and go to default factory settings mode.
ANY time the device receives a reply indicating it has been deleted as a result of the /cloudprint/printer API (startup, update settings notification, daily ping), it MUST delete its credentials and go to default mode.
4.2. /privet/info API
The info API is MANDATORY and MUST be implemented by every device. It is an HTTP GET request for "/privet/info" url: GET /privet/info HTTP/1.1
The info API returns basic information about a device and functionality it supports. This API MUST never change the device status or perform any action, since it is vulnerable to XSRF attacks. This is the ONLY API allowed to have an empty "X-Privet-Token" header. Clients should call /privet/info API with "X-Privet-Token" header set to X-Privet-Token: ""
The info API MUST return data consistent with data available in the TXT record during discovery.
4.2.1. Input
/privet/info API has no input parameters.
4.2.2. Возвращаться
/privet/info API returns basic information about device and supported functionality.
The TXT column indicates the corresponding field in the DNS-SD TXT record.
Value Name | Value Type | Описание | TXT |
---|---|---|---|
version | string | Highest version (major.minor) of API supported, currently 1.0 | |
name | string | Human readable name of the device. | ty |
description | string | (optional) Device description. SHOULD be modifiable by user. | note |
url | string | URL of the server this device is talking to. URL MUST include protocol specification, for example: https://www.google.com/cloudprint. | url |
type | list of strings | List of device types supported. | type |
id | string | Device id, empty if device has not been registered yet. | id |
device_state | string | State of the device. idle means device is ready processing means device is busy and functionality may be limited for some time stopped means device is not working and user intervention is required | |
connection_state | string | State of the connection to the server (base_url) online - connection available offline - no connection connecting - performing startup steps not-configured - connection has not been configured yet A registered device may report its connection state based on the state of the notification channel (eg XMPP connection state). | cs |
manufacturer | string | Name of the device manufacturer | |
model | string | Model of the device | |
serial_number | string | Unique device identifier. In this spec, this MUST be a UUID. (GCP 1.1 spec) (optional) We strongly recommend using the same serial number ID everywhere, so different clients can identify the same device. For example, printers implementing IPP may use this serial number ID in "printer-device-id" field. | |
firmware | string | Device firmware version | |
uptime | int | Number of seconds from the device boot. | |
setup_url | string | (optional) URL (including protocol) of the page with setup instructions | |
support_url | string | (optional) URL (including protocol) of the page with support, FAQ information | |
update_url | string | (optional) URL (including protocol) of the page with update firmware instructions | |
x-privet-token | string | Value of the X-Privet-Token header that has to be passed to all APIs to prevent XSSI and XSRF attacks. See 6.1. for details. | |
api | description of APIs | List of supported APIs (described below) | |
semantic_state | JSON | (optional) Semantic state of the device in CloudDeviceState format. |
api - is a JSON list containing the list of APIs available through the local network. Note that not all APIs may be available at the same time over the local network. For example, a newly connected device should only support the /register api:
"api": [ "/privet/register", ]Once device registration is complete, the device SHOULD stop supporting the /register API. The device should also check with the service to provide what APIs can be exposed over the local network. For example:
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
The following APIs are available at this time:
- /privet/register - API for device registration over the local network. (see /privet/register API for details). This API MUST be hidden once the device is successfully registered in the cloud.
- /privet/accesstoken - API to request access token from the device (see /privet/accesstoken API for details).
- /privet/capabilities - API to retrieve device capabilities (see /privet/capabilities API for details).
- /privet/printer/* - API specific to the device type "printer", see printer specific APIs for details.
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "idle", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ] }Here is an example of the /privet/info response for a printer that ran out of ink (notice semantic_state field):
{ "version": "1.0", "name": "Gene’s printer", "description": "Printer connected through Chrome connector", "url": "https://www.google.com/cloudprint", "type": [ "printer" ], "id": "11111111-2222-3333-4444-555555555555", "device_state": "stopped", "connection_state": "online", "manufacturer": "Google", "model": "Google Chrome", "serial_number": "1111-22222-33333-4444", "firmware": "24.0.1312.52", "uptime": 600, "setup_url": "http://support.google.com/cloudprint/answer/1686197/?hl=en", "support_url": "http://support.google.com/cloudprint/?hl=en", "update_url": "http://support.google.com/cloudprint/?hl=en", "x-privet-token": "AIp06DjQd80yMoGYuGmT_VDAApuBZbInsQ:1358377509659", "api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ], "semantic_state": { "version": "1.0", "printer": { "state": "STOPPED", "marker_state": { "item": [ { "vendor_id": "ink", "state": "EXHAUSTED", "level_percent": 0 } ] } } } }
4.2.3. Errors
/privet/info API should ONLY return an error if X-Privet-Token header is missing. It MUST be HTTP 400 error:
HTTP/1.1 400 Missing X-Privet-Token header.
4.3. /privet/register API
/privet/register API is OPTIONAL. It is an HTTP POST request. /privet/register API MUST check for a valid X-Privet-Token header. Device MUST implement this API on "/privet/register" url:
POST /privet/register?action=start&user=user@domain.com HTTP/1.1 POST /privet/register?action=complete&user=user@domain.com HTTP/1.1
The device should expose /privet/register API ONLY when it allows anonymous registration at the moment. For example:
- When the device is turned on (or after clicking a special button on the device) and has not been registered yet, it should expose the /privet/register API to allow a user from the local network to claim the printer.
- After registration is complete, the device should stop exposing the /privet/register API to prevent another user on the local network from reclaiming the device.
- Some devices may have different ways to register devices and should not expose the /privet/register API at all (for example, Chrome Cloud Print connector).
The registration process consists of 3 steps (see anonymous registration for Cloud Print).
- Initiate anonymous registration process.
- A client initiates this process by calling the /privet/register API. The device may wait for user confirmation at that time.
- Get claim token.
The client polls to find out when the device is ready to continue. Once the device is ready, it sends a request to the server to retrieve registration token and registration URL. Received token and URL SHOULD be returned to the client. During this step, if the device receives another call to initialize registration, it should:
- If this is the same user who started registration - drop all previous data (if any) and start a new registration process.
- If this is different user - return device_busy error and 30 seconds timeout.
Complete registration process.
After the client has claimed the device, the client should notify the device to complete registration. Once the registration process is complete, the device should send an update announcement, including the newly acquired device id.
Note: When the device is processing a /privet/register API call, no other /privet/register API calls may be processed simultaneously. The device MUST return the device_busy error and 30 seconds timeout.
User confirmation for registration on the device is HIGHLY recommended. If implemented, the device MUST wait for user confirmation AFTER it receives a /privet/register?action=start API call. The client will be calling /privet/register?action=getClaimToken API to find out when user confirmation is complete and claim token is available. If the user cancels registration on the device (eg presses the Cancel button), the user_cancel error MUST be returned. If the user has not confirmed registration within a certain timeframe, the confirmation_timeout error MUST be returned. See defaults section for more details.
4.3.1. Input
/privet/register API has the following input parameters:Имя | Value |
---|---|
action | Can be one of the following: start - to start registration process getClaimToken - retrieve claim token for the device cancel - to cancel registration process complete - to complete registration process |
user | Email of the user who will claim this device. |
The device MUST check that the email address from all actions (start, getClaimToken, cancel, complete) matches.
4.3.2. Возвращаться
/privet/register API returns following data:Value name | Value type | Описание |
---|---|---|
action | string | Same action as in input parameter. |
user | string (optional) | Same user as in input parameter (may be missing, if omitted in the input). |
token | string (optional) | Registration token (mandatory for "getClaimToken" response, omitted for "start", "complete", "cancel"). |
claim_url | string (optional) | Registration URL (mandatory for "getClaimToken" response, omitted for "start", "complete", "cancel"). For Cloud Printers it must be the "complete_invite_url" received from the server. |
automated_claim_url | string (optional) | Registration URL (mandatory for "getClaimToken" response, omitted for "start", "complete", "cancel"). For Cloud Printers it must be the "automated_invite_url" received from the server. |
device_id | string (optional) | New device id (omitted for "start" response, mandatory for "complete"). |
The device MUST return its device id in the /privet/info API response ONLY after registration is complete.
Example 1:
{ "action": "start", "user": "user@domain.com", }
Example 2:
{ "action": "getClaimToken", "user": "user@domain.com", "token": "AAA111222333444555666777", "claim_url": "https://domain.com/SoMeUrL", }
Example 3:
{ "action": "complete", "user": "user@domain.com", "device_id": "11111111-2222-3333-4444-555555555555", }
4.3.3. Errors
/privet/register API may return following errors (see Errors section for details):Error | Описание |
---|---|
device_busy | The device is busy and can't perform the requested action. Retry after timeout. |
pending_user_action | In response to "getClaimToken" this error indicates that the device is still pending user confirmation, and "getClaimToken" request should be retried after timeout. |
user_cancel | User explicitly cancelled registration process from the device. |
confirmation_timeout | User confirmation times out. |
invalid_action | Invalid action is called. For example, if client called action=complete before calling action=start and action=getClaimToken. |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility). For example, return this if the client called action=unknown or user=. |
device_config_error | Date/Time (or some other settings) is wrong on the device side. User needs to go (to device internal website) and configure device settings. |
offline | The device is currently offline and can't talk to the server. |
server_error | Server error during registration process. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
The device MUST stop exposing the /privet/register API after registration has been successfully completed. If the device is not exposing the /privet/register API, it MUST return HTTP 404 error. Therefore, if a device is already registered, calling this API MUST return 404. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
4.4. /privet/accesstoken API
/privet/accesstoken API is OPTIONAL. It is an HTTP GET request. /privet/accesstoken API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on the "/privet/accesstoken" url:GET /privet/accesstoken HTTP/1.1
When the device receives the /accesstoken API call, it should call the server to retrieve the access token for the given user and return the token to the client. The client will then use the access token to access this device through the cloud.
Cloud Print devices MUST call the following API:
/cloudprint/proximitytokenand pass "printerid=<printer_id>" and "user" parameter from the local API. If successful, the server response will contain the following object:
"proximity_token": { "user": "user@domain.com", "token": "AAA111222333444555666777", "expires_in": 600 }Cloud Print devices MUST pass the value of the "proximity_token" object in the response to local /privet/accesstoken API calls. It is more advantageous (future-proof) if the device can pass ALL parameters (including ones that are not described in this spec).
4.4.1. Input
/privet/accesstoken API has the following input parameters:Имя | Value |
---|---|
user | Email of the user who intended to use this access token. May be empty in the request. |
4.4.2. Возвращаться
/privet/accesstoken API returns following data:Value name | Value type | Описание |
---|---|---|
token | string | Access token returned by the server |
user | string | Same user as in input parameter. |
expires_in | int | Number of seconds until this token expires. Received from the server and passed in this response. |
Example:
{ "token": "AAA111222333444555666777", "user": "user@domain.com", "expires_in": 600 }
4.4.3. Errors
/privet/accesstoken API may return the following errors (see Errors section for details):Error | Описание |
---|---|
offline | Device is currently offline and can't talk to the server. |
access_denied | Insufficient rights. Access denied. The device should return this error when the request has been explicitly denied by the server. |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility). For example, if client called /accesstoken?user= or /accesstoken. |
server_error | Server error. |
invalid_x_privet_token | X-Privet-Token is Invalid or empty in the request. |
If the device is not exposing the /privet/accesstoken API, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
4.5. /privet/capabilities API
/privet/capabilities API is OPTIONAL. It is an HTTP GET request. /privet/capabilities API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/capabilities" url:GET /privet/capabilities HTTP/1.1When the device receives /capabilities API call, if the device is able, it SHOULD contact the server to get updated capabilities. For example, if a printer supports posting a print job (received locally) to itself through the Cloud Print service, it should return capabilities that the Cloud Print service would return. Cloud Print in this case may alter the original printer capabilities by adding new features it may perform before sending job to the printer. The most common case is a list of supported document types. If the printer is offline, it should return document types it supports. However, if the printer is online and registered with Cloud Print it MUST return "*/*" as one of the supported types. The Cloud Print service will perform the necessary conversion in this case. For offline printing, the printer MUST support at least the "image/pwg-raster" format.
4.5.1. Input
/privet/capabilities API has the following input parameters:Имя | Value |
---|---|
offline | (optional) Can only be "offline=1". In this case the device should return capabilities for offline use (if they are different from "online" capabilities). |
4.5.2. Возвращаться
/privet/capabilities API returns device capabilities in the Cloud Device Description (CDD) JSON format (see the CDD document for details). Printers at minimum MUST return a list of supported types here. For example, a Cloud Ready printer that is currently online may return something like this (at minimum):{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" }, { "content_type": "*/*" } ] } }and when it's disconnected from the server, it may return:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "application/pdf", "min_version": "1.4" }, { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }
Note : Printers express supported content type priority using order. For example, in the samples above, the printer specifies that it prefers "application/pdf" data over "image/pwg-raster" and "image/jpeg". Clients should respect printer prioritization if possible (see the CDD document for details).
4.5.3. Errors
/privet/capabilities API may return following errors (see Errors section for details):Error | Описание |
---|---|
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If the device is not exposing the /privet/capabilities API, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
4.6. Errors
Errors are returned from the above APIs in the following format:Value name | Value type | Описание |
---|---|---|
error | string | Error type (defined per API) |
description | string (optional) | Human readable description of the error. |
server_api | string (optional) | In case of server error, this field contains the server API that failed. |
server_code | int (optional) | In case of server error, this field contains that error code that the server returned. |
server_http_code | int (optional) | In case of server HTTP error, this field contains HTTP error code server returned. |
timeout | int (optional) | Number of seconds for client to wait before retrying (for recoverable errors only). Client MUST randomize actual timeout from this value to a value that is + 20%. |
All APIs MUST return HTTP 400 error if X-Privet-Token header is missing.
HTTP/1.1 400 Missing X-Privet-Token header.
Example 1:
{ "error": "server_error", "description": "Service unavailable", "server_api": "/submit", "server_http_code": 503 }
Example 2:
{ "error": "printer_busy", "description": "Printer is currently printing other job", "timeout": 15 }
5. Printer API
One of the device types this protocol supports is type printer. Devices supporting this type MAY implement some functionality specific to printers. Ideally, printing to cloud-ready printers will go through a Cloud Print server:
![](https://developers.google.cn/cloud-print/images/privet_image07.jpg?authuser=3&hl=ru)
In some cases a client may need to send a document locally. It may be needed when client does not have a Google ID or is unable to talk to the Cloud Print server. In such case, the print job will be submitted locally to the printer. The printer, in turn, will use the Cloud Print service for job queueing and conversion. The printer will re-post the job submitted locally to the Cloud Print service and then request it, since it was submitted through the cloud. This process will provide a flexible user experience in terms of service (conversion) and print job management/tracking.
![](https://developers.google.cn/cloud-print/images/privet_image08.jpg?authuser=3&hl=ru)
Since the Cloud Print service implements conversion, the printer SHOULD advertise supporting all input formats ("*/*") among the list of the supported content types:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "*/*" } ] } }
In some cases a completely offline solution is desired. Since printers support a limited number of input formats, a client will need to convert documents to a few natively supported printer formats.
![](https://developers.google.cn/cloud-print/images/privet_image04.jpg?authuser=3&hl=ru)
This spec REQUIRES all printers to support at least the PWG Raster ("image/pwg-raster") format for the offline printing case. A printer may support other formats (for example JPEG) and if a client supports it, it may send documents in that format. The printer MUST expose supported types through the /capabilities API, for example:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }There are two ways a client may initiate printing over the local network.
Simple printing - client sends the document over the local network to /submitdoc API (without specifying the job_id parameter). The submitted document will be printed using default print ticket settings and no print job statuses are needed. If the printer ONLY supports this type of printing, it MUST advertise ONLY /submitdoc API in the /privet/info API response.
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
Advanced printing - client should first create a print job on the printer by calling the /privet/printer/createjob API with a valid CJT job ticket in the request. The printer MUST store the print ticket in memory and return a job_id back to the client. Then the client will call the /printer/submitdoc API and specify the previously received job_id . At that time the printer will start printing. The client will poll the printer for print job status by calling the /privet/printer/jobstate API.
In a multi-client environment, there is no guarantee how this API is called. It is possible for one client to call /createjob between another client's /createjob->/submitdoc calls. To eliminate possible deadlocks and improve usability, we recommended having a small queue of pending print jobs on the printer (at least 3-5):
- /createjob takes the first available spot in the queue.
- Job lifetime (in the queue) is at least 5 minutes.
- If all spots in the queue are taken, then the oldest, non-printing job shall be removed and a new one will be placed there.
- If there is a print job currently printing on the device (simple or advanced printing), /submitdoc should return status busy and propose a timeout to retry this print job.
- If /submitdoc refers to a job that has been removed from the queue (due to replacement or timeout), the printer should return an error invalid_print_job and the client will retry the process from the /createjob step. The client MUST wait for a random timeout period of up to 5 seconds before retrying.
If memory constraints prevent storing multiple pending jobs on the device, it is possible to have a queue of 1 print job long. It should still follow the same protocol as above. After a job has completed or failed with an error, the printer should store information about the job's status for at least 5 minutes. The queue size for storing completed job statuses should be at least 10. If there are more job statuses that need to be stored, the oldest one may be removed from the queue before the 5 minute timeout.
Note: For now clients will poll for job status. In the future, we may require the printer to send TXT DNS notification when ANY print job status has changed.
5.1. /privet/printer/createjob API
/privet/printer/createjob API is OPTIONAL (see Simple Printing above). It is an HTTP POST request. /privet/printer/createjob API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/createjob" url:
POST /privet/printer/createjob HTTP/1.1When receiving /privet/printer/createjob API call, the printer MUST create a new print job ID, store the received print ticket in the CJT format, and return print job id back to the client.
5.1.1. Input
/privet/printer/createjob API has no input parameters in URL. The request body should contain the print job ticket data in CJT format.5.1.2. Возвращаться
/privet/printer/createjob API returns the following data:Value name | Value type | Описание |
---|---|---|
job_id | string | ID of the newly created print job. |
expires_in | int | Number of seconds this print job is valid. |
Example:
{ "job_id": "123", "expires_in": 600 }
5.1.3. Errors
/privet/printer/createjob API may return the following errors (see Errors section for details):Error | Описание |
---|---|
invalid_ticket | Submitted print ticket is invalid. |
printer_busy | Printer is busy and can't currently process /createjob. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/createjob it MUST return HTTP 404 error. If X-Privet-Token header is missing, the device MUST return HTTP 400 error.
5.2. /privet/printer/submitdoc API
/privet/printer/submitdoc API is REQUIRED to implement printing over a local network (offline or repost to Cloud Print). It is an HTTP POST request. /privet/printer/submitdoc API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/submitdoc" url:POST /privet/printer/submitdoc HTTP/1.1When receiving the /privet/printer/submitdoc API call, the printer should start printing. If it is unable to begin printing, it MUST return the error printer_busy and a recommended timeout period for the client to wait before trying again.
If the printer is not able to hold all of the data in its internal buffer, it SHOULD use TCP mechanisms to slow down data transfer until it prints a portion of the document, making part of the buffer available again. (For example, the printer may set windowsize=0 on TCP layers, which will make the client wait.)
Submitting a document to the printer may take a significant amount of time. The client should be able to check the state of the printer and job (advanced printing) while printing is in progress. In order to do that, the printer MUST allow the client to call the /privet/info and /privet/printer/jobstate APIs while processing /privet/printer/submitdoc API calls. It is recommended for all clients to start a new thread to execute the /privet/printer/submitdoc API call, so that the main thread can use the /privet/info and /privet/printer/jobstate APIs to check printer and job states.
Note : Upon completion or abortion of the local print job, it is strongly recommended (and will be required in a future version of this spec) to report the final state of the job to the /cloudprint/submit interface for accounting and user experience purposes. The parameters "printerid", "title", "contentType" and "final_semantic_state" (in PrintJobState format) are required, and the parameters "tag" (repeated parameter) and "ticket" (the ticket of the job in CloudJobTicket format). Note that the provided PrintJobState must actually be final, ie its type must be DONE or ABORTED, and a cause must be provided in the case that it is ABORTED (see JobState for details). Also note that this use of the /cloudprint/submit interface to report local print jobs is not mentioned in its specification because that section is intended to describe the interface's primary use: submitting a print job with the document to print provided in the "content" parameter.
5.2.1. Input
/privet/printer/submitdoc API has the following input parameters:Имя | Value |
---|---|
job_id | (optional) Print job id. May be omitted for simple printing case (see above). Must match the one returned by the printer. |
user_name | (optional) Human readable user name. This is not definitive, and should only be used for print job annotations. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
client_name | (optional) Name of the client application making this request. For display purposes only. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
job_name | (optional) Name of the print job to be recorded. If job is re-posted to the Cloud Print service this string should be attached to the Cloud Print job. |
offline | (optional) Could only be "offline=1". In this case printer should only try printing offline (no re-post to Cloud Print server). |
Request body should contain a valid document for printing. "Content-Length" should include the correct length of the request. "Content-Type" header should be set to document MIME type and match one of the types in the CDD (unless CDD specifies "*/*").
Clients are HIGHLY recommended to provide a valid user name (or email), a client name and a job name with this request. Those fields are only used in UIs to improve user experience.
5.2.2. Возвращаться
/privet/printer/submitdoc API returns following data:Value name | Value type | Описание |
---|---|---|
job_id | string | ID of the newly created print job (simple printing) or job_id specified in the request (advanced printing). |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | Content-type of the submitted document. |
job_size | int 64 bit | Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
Example:
{ "job_id": "123", "expires_in": 500, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
5.2.3. Errors
/privet/printer/submitdoc API may return the following errors (see Errors section for details):Error | Описание |
---|---|
invalid_print_job | Invalid/expired job id is specified in the request. Retry after timeout. |
invalid_document_type | Document MIME-type is not supported by the printer. |
invalid_document | Submitted document is invalid. |
document_too_large | Document exceeds maximum size allowed. |
printer_busy | Printer is busy and can't currently process document. Retry after timeout. |
printer_error | Printer is in error state and requires user interaction to fix it. Description should contain more detailed explanation (eg "Paper jam in Tray 1"). |
invalid_params | Invalid parameters specified in the request. (Unknown parameters should be safely ignored for future compatibility) |
user_cancel | User explicitly cancelled printing process from the device. |
server_error | Posting document to Cloud Print has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If the device is not exposing /privet/printer/submitdoc, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
Note : /privet/printer/submitdoc API may require special handling on printer side (because of the large payload attached). In some cases (depends on the printer HTTP server implementation and platform), printer may close socket BEFORE returning HTTP error. In other, printer may return 503 error (instead of Privet error). Printers SHOULD try as much as possible to return Privet. However, every client implementing Privet specification SHOULD be able to handle socket close (no HTTP error) and 503 HTTP error cases for /privet/printer/submitdoc API. In this case, client SHOULD handle it as a Privet "printer_busy" error with "timeout" set to 15 seconds. To avoid infinite retries, client may stop retrying after a reasonable number of attempts (for example, 3).
5.3. /privet/printer/jobstate API
/privet/printer/jobstate API is OPTIONAL (see Simple Printing above). It is an HTTP GET request. /privet/printer/jobstate API MUST check for a valid "X-Privet-Token" header. The device MUST implement this API on "/privet/printer/jobstate" url:GET /privet/printer/jobstate HTTP/1.1When receiving a /privet/printer/jobstate API call, a printer should return the status of the requested print job or invalid_print_job error.
5.3.1. Input
/privet/printer/jobstate API has following input parameters:Имя | Value |
---|---|
job_id | Print job ID to return status for. |
5.3.2. Возвращаться
/privet/printer/jobstate API returns the following data:Value name | Value type | Описание |
---|---|---|
job_id | string | Print job id there status information is for. |
state | string | draft - print job has been created on the device (no /privet/printer/submitdoc calls have been received yet). queued - print job has been received and queued, but printing has not started yet. in_progress - print job is in the progress of printing. stopped - print job has been paused, but can be restarted manually or automatically. done - print job is done. aborted - print job failed. |
description | string | (optional) Human readable description of the print job status. Should include additional information if state < is stopped or aborted . The semantic_state field usually provides better and more meaningful description to the client. |
expires_in | int | Number of seconds this print job is valid. |
job_type | string | (optional) Content-type of the submitted document. |
job_size | int 64 bit | (optional) Size of the print data in bytes. |
job_name | string | (optional) Same job name as in input (if any). |
server_job_id | string | (optional) ID of the job returned from the server (if job has been posted to Cloud Print service). Omitted for offline printing. |
semantic_state | JSON | (optional) Semantic state of the job in PrintJobState format. |
Example (printing by reporting through Cloud Print):
{ "job_id": "123", "state": "in_progress", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "server_job_id": "1111-2222-3333-4444" }
Example (offline printing error):
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
Example (print job aborted by the user):
{ "job_id": "123", "state": "aborted", "description": "User action", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"} }, "pages_printed": 7 } }
Example (print job stopped due to out of paper). Notice the reference to the device state. The client will need to call the /privet/info API to get more details about the device state:
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": "123456", "job_name": "My PDF document", "semantic_state": { "version": "1.0", "state": { "type": "STOPPED", "device_state_cause": {"error_code": "INPUT_TRAY"} }, "pages_printed": 7 } }
5.3.3. Errors
/privet/printer/jobstate API may return the following errors (see Errors section for details):Error | Описание |
---|---|
invalid_print_job | Invalid/expired job ID is specified in the request. |
server_error | Getting print job status (for print jobs posted to Cloud Print) has failed. |
invalid_x_privet_token | X-Privet-Token is invalid or empty in the request. |
If device is not exposing /privet/printer/jobstate, it MUST return HTTP 404 error. If the X-Privet-Token header is missing, the device MUST return HTTP 400 error.
6. Appendix
6.1. Default behavior and settings
This section will explain the default behavior we expect from ALL Privet-compatible devices.- Out-of-the-box devices should support only /privet/info and /privet/register APIs. All other APIs (eg /privet/accesstoken, local printing) should be disabled.
- Registration requires physical interaction with a device.
- User MUST take a physical action on the device (eg, pressing a button) to confirm their access to the device.
- After the user takes the action noted above, the printer should send the /cloudprint/register request. It should not send this request until after the action is taken (see Sequence Diagram 1).
- If the device is processing a /privet/register request (for instance, waiting on the action above), it must reject all other /privet/register requests. The device MUST return the device_busy error in this case.
- The device should timeout any /register request that does not receive the physical action mentioned above within 60 seconds. The device MUST return the confirmation_timeout error in this case.
- Optional: Recommended but not required, the following may improve user experience:
- The printer might flash a light or its screen to indicate that the user needs to take an action to confirm registration.
- The printer might state on its screen that 'it is being registered to Google Cloud Print for user ' abc@def.com ' - press OK to continue', where abc@def.com is the user parameter from the /register API call. This would make it clearer to a user that:
- it is their registration request that they are confirming
- what is happening if s/he didn't trigger the request.
- In addition to a physical action to confirm from the printer (eg, 'Press the OK button'), a printer may also offer the user a button to cancel the request (eg, 'Press Cancel to reject'). This would allow users who did not trigger the registration request to cancel it before the 60 second timeout. The device MUST return the user_cancel error in this case.
- Ownership transfers:
- The device may be deleted explicitly from the Cloud service.
- If the device receives success, but no device description as a result of /cloudprint/printer (for GCP) call, it MUST revert to default (out-of-the-box) mode.
- If the device's credentials no longer work (explicitly because of "invalid credentials" response from the server), it MUST revert to default (out-of-the-box) mode.
- Local factory reset MUST clear device's credentials and set it to default state.
- Optional: The device may provide a menu item to clear credentials and put it into default mode.
- Devices supporting XMPP notifications MUST include the ability to ping the server. The ping timeout MUST be controllable from the server through "local_settings".
- The device may explicitly ping the server (/cloudprint/printer API for GCP, in addition to XMPP pings) no more often than once a day (24 hours) to make sure they are in sync. It is recommended to randomize the check window within 24-32 hour window.
- Optional: For Cloud Print devices, it is recommended but not required to have a manual way (button) to allow the user to initiate a check for new print jobs from the device. Some printers already have this.
- Optional. Enterprise printers may have an option to disable local discovery completely. In such case, the device MUST update these local settings on the server. New local settings MUST be empty (setting "local_discovery" to "false", means that it can be re-enabled from the GCP Service).
6.1.2 Default Registration Diagram
![](https://developers.google.cn/cloud-print/images/privet_image06.png?authuser=3&hl=ru)
6.2. XSSI and XSRF attacks and prevention
This section will explain the possibility of XSSI and XSRF attacks on the device and how to protect from them (including token generation techniques).More details are here: http://googleonlinesecurity.blogspot.com/2011/05/website-security-for-webmasters.html
Normally, XSSI and XSRF attacks are possible when a site is using cookie authentication mechanisms. While Google doesn't use cookies with their Cloud Print Service, such attacks are still possible. Local network access, by design, implicitly trusts requests.
6.2.1. XSSI
It is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and to try to call the Privet API using "src=<api name>" inside of a <script> tag:<script type="text/javascript" src="http://192.168.1.42:8080/privet/info"></script>Without protection, malicious websites would be able to execute API calls and access results.
To prevent this type of attack, ALL Privet API calls MUST require the "X-Privet-Token" header in the request. "src=<api>" script tags are not able to add headers, effectively guarding against this type of attack.
6.2.2. XSRF
http://en.wikipedia.org/wiki/Cross-site_request_forgeryIt is possible for a malicious website to guess the IP address and port number of a Privet-compatible device and try to call Privet API using an <iframe>, forms, or some other cross-website loading mechanism. Attackers would not be able to access the results of the request, but if the request would perform an action (eg printing), they could trigger it.
To prevent this attack, we require the following protection:
- Leave /privet/info API open to XSRF
- /privet/info API MUST NOT perform any actions on the device
- Use /privet/info API to receive x-privet-token
- All other APIs MUST check for a valid x-privet-token in "X-Privet-Token" header.
- x-privet-token SHOULD be valid for only 24 hours.
Even if an attacker is able to execute the /privet/info API, they would not be able to read x-privet-token from the response and therefore would not be able to call any other API.
It is strongly recommended to generate the XSRF token using the following algorithm:
XSRF_token = base64( SHA1(device_secret + DELIMITER + issue_timecounter) + DELIMITER + issue_timecounter )
XSRF Token Generation Elements:
- DELIMITER is a special character, usually ':'
- issue_timecounter is a number of seconds since some event (epoch for timestamp) or device boot time (for CPU counters). issue_timecounter is constantly increasing when the device is up and running (see token verification below).
- SHA1 - hash function using SHA1 algorithm
- base64 - base64 encoding
- device_secret - secret specific to the device. Device secret MUST be updated on every restart.
Recommended ways to generate device secret:
- Generate a new UUID on every restart
- Generate a 64 bit random number on every restart
The device is not required to store all of the XSRF tokens it has issued. When the device needs to verify a XSRF token for validity, it should base64-decode the token. Get the issue_timecounter from the second half (cleartext), and try to produce SHA1 hash of device_secret + DELIMITER + issue_timecounter where issue_timecounter is from the token. If the newly generated SHA1 matches the one in the token, device must now check if the issue_timecounter is within the validity period from (24 hours) of the current time counter. To do so, device takes the current time counter (CPU counter for example) and subtracts issue_timecounter from it. The result MUST be the number of seconds since token issue.
Important: This is the recommended way to implement XSRF protection. Clients of the Privet specification shall not try to understand XSRF token, instead they shall treat is as a blackbox. Figure 6.2.3 illustrates a recommended way to implement the X-Privet-Token and verification of a typical request.
6.2.3 X-Privet Token Generation and Verification Sequence Diagram
![](https://developers.google.cn/cloud-print/images/privet_image03.png?authuser=3&hl=ru)
6.3. Workflow diagrams
This section will illustrate a workflow in different cases.6.3.1. Printer out of the box workflow
![](https://developers.google.cn/cloud-print/images/privet_image01.png?authuser=3&hl=ru)
6.3.2. Registered printer startup
![](https://developers.google.cn/cloud-print/images/privet_image02.png?authuser=3&hl=ru)
6.3.3 XMPP notifications handling workflow
![](https://developers.google.cn/cloud-print/images/privet_image05.png?authuser=3&hl=ru)
6.3.4. Check printer settings workflow
![](https://developers.google.cn/cloud-print/images/privet_image00.png?authuser=3&hl=ru)