Privet 是雲端服務使用的 Cloud Device Local Discovery API。本文件分為以下幾個部分:
1. 簡介
連上雲端的裝置有許多優點。他們可以使用線上轉換服務、在裝置離線時代管工作佇列,以及從世界各地存取。不過,如果使用者可存取許多雲端裝置,我們就需要提供方法,根據位置資訊找出最近的裝置。Privet 通訊協定的目的是將雲端裝置的彈性與適當的本機探索機制繫結,讓裝置在新環境中輕鬆探索。
這項通訊協定的目標如下:- 讓雲端裝置可供本機探索
- 向雲端服務註冊雲端裝置
- 將註冊裝置與雲端代表建立關聯
- 啟用離線功能
- 簡化實作程序,讓小型裝置也能使用
Privet 通訊協定包含 2 個主要部分:探索和 API。探索功能可用於尋找區域網路上的裝置,而 API 則可用於取得裝置資訊及執行某些動作。本文中的「裝置」是指實作 Privet 通訊協定的雲端連線裝置。
2. 探索
探索功能採用無須調整設定 (mDNS 和 DNS-SD) 的通訊協定。裝置「必須」實作 IPv4 連結本機定址。裝置必須符合 mDNS 和 DNS-SD 規格。
- http://www.rfc-editor.org/rfc/rfc3927.txt (IPv4 連結本機)
- 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
裝置也可以實作其他服務類型。建議您為裝置實作的所有服務類型使用相同的服務執行個體名稱。舉例來說,印表機可能會實作「Printer XYZ._privet._tcp」和「Printer XYZ._printer._tcp」服務。這可簡化使用者的設定程序。不過,Privet 用戶端只會尋找「__privet._tcp」。
除了主要服務類型,裝置也「必須」為對應的子類型宣傳 PTR 記錄 (請參閱 DNS-SD 規格:「7.1. 選擇性執行個體列舉 (子類型)」。 格式應如下所示: _<subtype>._sub._privet._tcp
目前支援的裝置子類型只有「printer」。因此,所有印表機都「必須」宣傳 兩筆 PTR 記錄:
- _privet._tcp.local.
- _printer._sub._privet._tcp.local.
2.2. TXT 記錄
DNS 服務探索會定義欄位,以便在 TXT 記錄中新增服務的選用資訊。TXT 記錄是由鍵/值組合所組成。每個鍵/值組合都以長度位元組開頭,後面最多可接 255 個位元組的文字。鍵是第一個「=」字元前的文字,值則是第一個「=」字元後的文字,直到結尾為止。規格允許記錄中沒有值,在這種情況下,不會有「=」字元,或「=」字元後沒有文字。(請參閱 DNS-SD 規格: 「6.1. DNS TXT 記錄的一般格式規則」,瞭解 DNS TXT 記錄格式,以及「6.2. DNS-SD TXT 記錄大小」一節,瞭解建議長度)。
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
提供使用者可理解的裝置名稱。例如:
ty=Google Cloud Ready Printer Model XYZ
2.2.3. 附註 (選填)
提供使用者可理解的裝置名稱。例如:
note=1st floor lobby printer
注意:這是選用金鑰,可以略過。不過,如果存在,使用者「應該」可以修改這個值。註冊裝置時必須使用相同的說明。
2.2.4. url
這部裝置連線的伺服器網址 (包括通訊協定)。例如:
url=https://www.google.com/cloudprint
2.2.5. type
以半形逗號分隔的裝置子類型清單,列出這部裝置支援的子類型。格式為: 「type=_subtype1,_subtype2」。目前唯一支援的裝置子類型是印表機。
type=printer
列出的每個子類型都應使用對應的 PTR 記錄進行宣傳。每個支援的服務子類型都應有一個對應項目。服務子類型名稱 (<subtype>._sub._privet._tcp) 應與此處的裝置類型相同。
2.2.6. id
裝置 ID。如果裝置尚未註冊,這個鍵應該會存在,但值應為空白。例如:
id=11111111-2222-3333-4444-555555555555 id=
2.2.7. cs
顯示裝置目前的連線狀態。這項規格定義了四個可能的值。
- 「線上」表示裝置目前已連上雲端。
- 「離線」表示裝置可透過區域網路連線,但無法與伺服器通訊。
- 「連線中」表示裝置正在執行啟動程序,尚未完全連上網路。
- 「not-configured」表示裝置的網際網路存取權尚未設定。目前未使用這個值,但日後版本的規格可能會用到。
- cs=online
- cs=offline
- cs=connecting
如果裝置已向雲端註冊,啟動時應檢查與伺服器的連線,偵測連線狀態 (例如呼叫雲端 API 取得裝置設定)。裝置可能會使用通知管道 (例如 XMPP) 連線狀態來回報這個值。啟動時,未註冊的裝置可能會對網域執行 Ping 作業,以偵測連線狀態 (例如,對雲端列印裝置執行 Ping 作業 www.google.com)。
3. 公告事項
裝置啟動、關機或狀態變更時,裝置「必須」按照 mDNS 規格說明執行公告步驟。至少應傳送兩次相應的公告,且兩次公告之間至少間隔一秒。
3.1. 啟動
裝置啟動時,必須執行 mDNS 規格所述的探查和公告步驟。在這種情況下,應傳送 SRV、PTR 和 TXT 記錄。建議盡可能將所有記錄歸入一個 DNS 回應。如果不是,建議依下列順序新增:SRV、PTR、TXT 記錄。
3.2. 關閉
裝置關機時,系統「應」嘗試傳送 TTL=0 的「再見封包」(如 mDNS 文件所述),通知所有相關單位。
3.3. 更新
如果 TXT 中描述的任何資訊有變更,裝置「必須」傳送更新公告。在這種情況下,您只需要傳送新的 TXT 記錄。舉例來說,裝置註冊後「必須」傳送更新公告,其中包含新的裝置 ID。
4. API
發現雲端裝置後,用戶端即可透過本機網路直接與該裝置通訊。所有 API 都是以 HTTP 1.1 為基礎。資料格式以 JSON 為基礎。API 要求可以是 GET 或 POST 要求。
每個要求都必須包含有效的「X-Privet-Token」標頭。只有 /privet/info 要求可以有空白的「X-Privet-Token」標頭 (請注意,標頭仍須存在)。如果缺少「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」。 |
printer/local_printing_enabled | 布林值 (選填) | 指出是否應在區域網路上公開本機列印功能 (「/printer/createjob」、「/printer/submitdoc」、「/printer/jobstate」)。預設值應為「true」。 |
printer/conversion_printing_enabled | 布林值 (選填) | 指出本機列印是否可將工作傳送至伺服器進行轉換。只有在啟用本機列印時才有意義。 |
xmpp_timeout_value | int (選填) | 指出 XMPP 頻道 Ping 之間的秒數。預設值必須為 300 (5 分鐘) 以上。 |
重要事項:如果缺少任何選用值,表示裝置完全不支援對應功能。
4.1.2. 啟動
裝置啟動時,應與伺服器聯絡,確認可在區域網路中公開哪些 API。如果印表機已連上雲端列印,則應呼叫:
/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 } }
「current」物件表示目前生效的設定。
「pending」物件表示應套用至裝置的設定 (這個物件可能遺失)。
裝置看到「待處理」設定後,必須更新狀態 (請參閱下文)。
4.1.3. 更新
如果需要更新設定,系統會將 XMPP 通知傳送至裝置。通知的格式如下:
<device_id>/update_settings
收到這類通知後,裝置「必須」查詢伺服器,取得最新設定。 雲端列印裝置必須使用:
/cloudprint/printer?printerid=<printer_id>
裝置透過 /cloudprint/printer API (在啟動時或因通知而) 看到「待處理」部分後,就必須更新內部狀態,記住新設定。它「必須」呼叫伺服器 API,確認新設定。如果是雲端印表機,裝置「必須」呼叫 /cloudprint/update API,並使用「local_settings」參數,就像註冊時一樣。
重新連線至 XMPP 管道時,裝置「必須」呼叫 /cloudprint/printer API,檢查自上次連線以來,本機設定是否有所變更。
4.1.3.1. 地區設定待處理
裝置用來呼叫伺服器 API 的「local_settings」參數絕不能包含「pending」部分。
4.1.3.2. 目前地區設定
只有裝置可以變更「local_settings」的「current」部分。 其他人則會變更「待處理」部分,並等待裝置將變更傳播到「目前」部分。
4.1.4. 離線
如果無法在啟動期間與伺服器聯絡,裝置必須在收到通知後使用最後已知的本機設定。
4.1.5. 從服務中刪除裝置
如果裝置已從服務 (例如 GCP) 中刪除,系統會將 XMPP 通知傳送至裝置。通知格式如下:
<device_id>/delete
收到這類通知後,裝置「必須」前往伺服器檢查狀態。雲端列印裝置必須使用:
/cloudprint/printer?printerid=<printer_id>
裝置必須收到 HTTP 回應,且 success=false,且沒有裝置/印表機說明。這表示裝置已從伺服器移除,且裝置必須清除憑證並恢復原廠設定模式。
只要裝置收到回覆,指出裝置已因 /cloudprint/printer API (啟動、更新設定通知、每日 Ping) 而遭到刪除,就必須刪除憑證並進入預設模式。
4.2. /privet/info API
資訊 API 為必要項目,每部裝置都必須實作。這是對「/privet/info」網址發出的 HTTP GET 要求:GET /privet/info HTTP/1.1
資訊 API 會傳回裝置的基本資訊,以及支援的功能。這個 API 絕不能變更裝置狀態或執行任何動作,因為這類 API 容易受到 XSRF 攻擊。這是唯一允許「X-Privet-Token」標頭為空白的 API。用戶端應呼叫 /privet/info API,並將「X-Privet-Token」標頭設為 X-Privet-Token:
資訊 API 必須傳回與探索期間 TXT 記錄中資料一致的資料。
4.2.1. 輸入
/privet/info API 沒有輸入參數。
4.2.2. 回攻員
/privet/info API 會傳回裝置和支援功能的基本資訊。
TXT 欄會指出 DNS-SD TXT 記錄中的對應欄位。
值名稱 | 值類型 | 說明 | TXT |
---|---|---|---|
版本 | 字串 | 支援的最高 API 版本 (主要版本.次要版本),目前為 1.0 | |
名稱 | 字串 | 裝置的易讀名稱。 | ty |
說明 | 字串 | (選用) 裝置說明。使用者「應」可修改。 | 記事 |
網址 | 字串 | 這部裝置通訊的伺服器網址。網址必須包含通訊協定規格,例如:https://www.google.com/cloudprint。 | 網址 |
類型 | 字串清單 | 支援的裝置類型清單。 | 類型 |
id | 字串 | 裝置 ID,如果裝置尚未註冊,則為空白。 | id |
device_state | 字串 | 裝置狀態。 idle 表示裝置已準備就緒 processing 表示裝置忙碌中,功能可能會暫時受限 stopped 表示裝置無法運作,需要使用者介入 | |
connection_state | 字串 | 與伺服器 (base_url) 的連線狀態
online - 連線可用 offline - 無連線 connecting - 正在執行啟動步驟 not-configured - 尚未設定連線 註冊裝置可能會根據通知管道的狀態 (例如 XMPP 連線狀態) 回報連線狀態。 | cs |
製造商 | 字串 | 裝置製造商名稱 | |
模型 | 字串 | 裝置型號 | |
serial_number | 字串 | 裝置的專屬 ID。在本規格中,這項屬性「必須」是 UUID。(GCP 1.1 規格)
(選用) 我們強烈建議在所有位置使用相同的序號 ID,這樣不同用戶端就能識別出同一部裝置。舉例來說,實作 IPP 的印表機可能會在「printer-device-id」欄位中使用這個序號 ID。 | |
韌體 | 字串 | 裝置韌體版本 | |
正常運行時間 | int | 裝置啟動後經過的秒數。 | |
setup_url | 字串 | (選用) 含有設定說明的網頁網址 (包括通訊協定) | |
support_url | 字串 | (選用) 包含支援和常見問題資訊的網頁網址 (包括通訊協定) | |
update_url | 字串 | (選用) 包含更新韌體說明的頁面網址 (包括通訊協定) | |
x-privet-token | 字串 | X-Privet-Token 標頭的值,必須傳遞至所有 API,以防範 XSSI 和 XSRF 攻擊。詳情請參閱 6.1 節。 | |
api | API 說明 | 支援的 API 清單 (如下所述) | |
semantic_state | JSON | (選用) 裝置的語意狀態,格式為 CloudDeviceState。 |
api - 是 JSON 清單,內含透過本機網路提供的 API 清單。請注意,並非所有 API 都能同時透過本機網路使用。舉例來說,新連線的裝置應只支援 /register API:
"api": [ "/privet/register", ]
"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", ] }
{ "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. 錯誤
只有在缺少 X-Privet-Token 標頭時,/privet/info API 才應傳回錯誤。這「必須」是 HTTP 400 錯誤:
HTTP/1.1 400 Missing X-Privet-Token header.
4.3. /privet/register API
/privet/register API 為選用。這是 HTTP POST 要求。/privet/register API 必須檢查有效的 X-Privet-Token 標頭。裝置必須在「/privet/register」網址上實作這項 API:
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。例如:
- 裝置開啟後 (或點選裝置上的特殊按鈕後),如果尚未註冊,就應公開 /privet/register API,讓區域網路使用者認領印表機。
- 註冊完成後,裝置應停止公開 /privet/register API,防止本機網路上的其他使用者回收裝置。
- 部分裝置可能採用不同的裝置註冊方式,且完全不應公開 /privet/register API (例如 Chrome 雲端列印連接器)。
註冊程序包含 3 個步驟 (請參閱「匿名註冊 Google 雲端列印」)。
- 啟動匿名註冊程序。
- 用戶端會呼叫 /privet/register API,啟動這項程序。裝置可能會等待使用者確認。
- 取得要求權杖。
用戶端會輪詢,瞭解裝置何時準備好繼續。裝置準備就緒後,會向伺服器傳送要求,以擷取註冊權杖和註冊網址。收到的權杖和網址「應」傳回給用戶端。在此步驟中,如果裝置收到另一個初始化註冊的呼叫,應採取下列行動:
- 如果這是開始註冊的同一位使用者,請捨棄所有先前的資料 (如有),然後開始新的註冊程序。
- 如果使用者不同,請傳回 device_busy 錯誤和 30 秒逾時。
完成註冊程序。
用戶端聲明擁有裝置後,應通知裝置完成註冊。註冊程序完成後,裝置應會傳送更新公告,包括新取得的裝置 ID。
注意:裝置處理 /privet/register API 呼叫時,無法同時處理其他 /privet/register API 呼叫。裝置「必須」傳回 device_busy 錯誤和 30 秒逾時。
強烈建議使用者在裝置上確認註冊。如果實作,裝置收到 /privet/register?action=start API 呼叫後,必須等待使用者確認。用戶端會呼叫 /privet/register?action=getClaimToken API,瞭解使用者何時完成確認,以及何時可取得聲明權杖。如果使用者在裝置上取消註冊 (例如按下「取消」按鈕),系統必須傳回 user_cancel 錯誤。如果使用者未在特定時間範圍內確認註冊,系統「必須」傳回 confirmation_timeout 錯誤。詳情請參閱「預設值」一節。
4.3.1. 輸入
/privet/register API 具有下列輸入參數:名稱 | 值 |
---|---|
動作 | 可以是下列其中一項:
start - 開始註冊程序 getClaimToken - 擷取裝置的聲明權杖 cancel - 取消註冊程序 complete - 完成註冊程序 |
使用者 | 將聲明擁有這部裝置的使用者電子郵件地址。 |
裝置「必須」檢查所有動作 (開始、getClaimToken、取消、完成) 的電子郵件地址是否相符。
4.3.2. 回攻員
/privet/register API 會傳回下列資料:值名稱 | 值類型 | 說明 |
---|---|---|
動作 | 字串 | 與輸入參數中的動作相同。 |
使用者 | 字串 (選填) | 與輸入參數中的使用者相同 (如果輸入內容中省略,則可能缺少)。 |
token | 字串 (選填) | 註冊權杖 (「getClaimToken」回應必須提供,但「start」、「complete」和「cancel」則可省略)。 |
claim_url | 字串 (選填) | 註冊網址 (「getClaimToken」回應必須提供,但「start」、「complete」和「cancel」則可省略)。如果是雲端印表機,則必須是從伺服器收到的「complete_invite_url」。 |
automated_claim_url | 字串 (選填) | 註冊網址 (「getClaimToken」回應必須提供,但「start」、「complete」和「cancel」則可省略)。如果是雲端印表機,則必須是從伺服器收到的「automated_invite_url」。 |
device_id | 字串 (選填) | 新裝置 ID (「start」回應中省略,但「complete」回應中必須提供)。 |
裝置必須在註冊完成後,才可透過 /privet/info API 回應傳回裝置 ID。
範例 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 可能會傳回下列錯誤 (詳情請參閱「錯誤」一節):錯誤 | 說明 |
---|---|
device_busy | 裝置忙碌中,無法執行要求的動作。逾時後重試。 |
pending_user_action | 如果「getClaimToken」傳回這個錯誤,表示裝置仍待使用者確認,逾時後應重試「getClaimToken」要求。 |
user_cancel | 使用者從裝置明確取消註冊程序。 |
confirmation_timeout | 使用者確認逾時。 |
invalid_action | 呼叫的動作無效。舉例來說,如果用戶端在呼叫 action=start 和 action=getClaimToken 之前,先呼叫了 action=complete。 |
invalid_params | 要求中指定的參數無效。(為確保日後相容性,應安全地忽略不明參數)。舉例來說,如果用戶端呼叫 action=unknown 或 user=,請傳回這個值。 |
device_config_error | 裝置端日期/時間 (或其他設定) 有誤。使用者必須前往裝置內部網站,並設定裝置設定。 |
離線 | 裝置目前處於離線狀態,無法與伺服器通訊。 |
server_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
/privet/accesstoken API 為選用項目。這是 HTTP GET 要求。/privet/accesstoken API 必須檢查有效的「X-Privet-Token」標頭。裝置「必須」在「/privet/accesstoken」網址上實作這個 API:GET /privet/accesstoken HTTP/1.1
裝置收到 /accesstoken API 呼叫時,應呼叫伺服器,為指定使用者擷取存取權杖,並將權杖傳回給用戶端。接著,用戶端會使用存取權杖,透過雲端存取這部裝置。
Cloud Print 裝置「必須」呼叫下列 API:
/cloudprint/proximitytoken
"proximity_token": { "user": "user@domain.com", "token": "AAA111222333444555666777", "expires_in": 600 }
4.4.1. 輸入
/privet/accesstoken API 具有下列輸入參數:名稱 | 值 |
---|---|
使用者 | 打算使用這個存取權杖的使用者電子郵件地址。要求中可能為空白。 |
4.4.2. 回攻員
/privet/accesstoken API 會傳回下列資料:值名稱 | 值類型 | 說明 |
---|---|---|
token | 字串 | 伺服器傳回的存取權杖 |
使用者 | 字串 | 與輸入參數中的使用者相同。 |
expires_in | int | 這個權杖的有效期限 (以秒為單位)。從伺服器接收,並傳遞至此回應。 |
範例:
{ "token": "AAA111222333444555666777", "user": "user@domain.com", "expires_in": 600 }
4.4.3. 錯誤
/privet/accesstoken API 可能會傳回下列錯誤 (詳情請參閱「錯誤」一節):錯誤 | 說明 |
---|---|
離線 | 裝置目前處於離線狀態,無法與伺服器通訊。 |
access_denied | 權利不足。存取遭拒,如果伺服器明確拒絕要求,裝置應傳回這項錯誤。 |
invalid_params | 要求中指定的參數無效。(為確保日後相容性,應安全地忽略不明參數)。舉例來說,如果用戶端呼叫 /accesstoken?user= 或 /accesstoken。 |
server_error | 伺服器錯誤。 |
invalid_x_privet_token | 要求中的 X-Privet-Token 無效或空白。 |
如果裝置未公開 /privet/accesstoken API,則必須傳回 HTTP 404 錯誤。如果缺少 X-Privet-Token 標頭,裝置必須傳回 HTTP 400 錯誤。
4.5. /privet/capabilities API
/privet/capabilities API 為選用項目。這是 HTTP GET 要求。/privet/capabilities API 必須檢查有效的「X-Privet-Token」標頭。裝置「必須」在「/privet/capabilities」網址上實作這個 API:GET /privet/capabilities HTTP/1.1
4.5.1. 輸入
/privet/capabilities API 具有下列輸入參數:名稱 | 值 |
---|---|
離線 | (選用) 只能是「offline=1」。在這種情況下,裝置應傳回離線使用功能 (如果與「線上」功能不同)。 |
4.5.2. 回攻員
/privet/capabilities API 會以 Cloud 裝置說明 (CDD) JSON 格式傳回裝置功能 (詳情請參閱 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 無效或空白。 |
如果裝置未公開 /privet/capabilities API,則必須傳回 HTTP 404 錯誤。如果缺少 X-Privet-Token 標頭,裝置必須傳回 HTTP 400 錯誤。
4.6. 錯誤
上述 API 會以以下格式傳回錯誤:值名稱 | 值類型 | 說明 |
---|---|---|
錯誤 | 字串 | 錯誤類型 (依 API 定義) |
說明 | 字串 (選填) | 使用者可理解的錯誤說明。 |
server_api | 字串 (選填) | 如果發生伺服器錯誤,這個欄位會包含失敗的伺服器 API。 |
server_code | int (選填) | 如果發生伺服器錯誤,這個欄位會包含伺服器傳回的錯誤代碼。 |
server_http_code | int (選填) | 如果發生伺服器 HTTP 錯誤,這個欄位會包含伺服器傳回的 HTTP 錯誤代碼。 |
逾時 | int (選填) | 用戶端等待重試的秒數 (僅適用於可復原的錯誤)。用戶端必須將實際逾時時間從這個值隨機化為 + 20% 的值。 |
如果缺少 X-Privet-Token 標頭,所有 API 都必須傳回 HTTP 400 錯誤。
HTTP/1.1 400 Missing X-Privet-Token header.
範例 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. Printer API
這個通訊協定支援的裝置類型之一是印表機。支援這類裝置的裝置「可能」會實作印表機專屬功能。理想情況下,列印至可雲端列印的印表機時,會透過雲端列印伺服器:

在某些情況下,用戶端可能需要在本機傳送文件。如果用戶端沒有 Google ID 或無法與雲端列印伺服器通訊,可能就需要這項功能。在這種情況下,列印工作會在本機提交至印表機。印表機則會使用雲端列印服務排隊及轉換工作。印表機會將本機提交的工作重新發布至雲端列印服務,然後要求該工作,因為工作是透過雲端提交。這項程序可提供彈性的服務 (轉換) 使用者體驗,以及列印工作管理/追蹤功能。

由於 Cloud Print 服務會實作轉換功能,印表機應在支援的內容類型清單中,宣傳支援所有輸入格式 (*/*):
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "*/*" } ] } }
在某些情況下,您可能需要完全離線的解決方案。由於印表機支援的輸入格式有限,用戶端必須將文件轉換為印表機原生支援的幾種格式。

這項規格「要求」所有印表機至少支援 PWG Raster (「image/pwg-raster」) 格式,以供離線列印。印表機可能支援其他格式 (例如 JPEG),如果用戶端支援,可能會以該格式傳送文件。印表機必須透過 /capabilities API 公開支援的類型,例如:
{ "version": "1.0", "printer": { "supported_content_type": [ { "content_type": "image/pwg-raster" }, { "content_type": "image/jpeg" } ] } }
簡單列印 - 用戶端透過本機網路將文件傳送至 /submitdoc API (未指定 job_id 參數)。系統會使用預設列印單設定列印提交的文件,不需要列印工作狀態。如果印表機「僅」支援這類列印作業,則「必須」在 /privet /info API 回應中「僅」宣傳/submitdoc API。
"api": [ "/privet/accesstoken", "/privet/capabilities", "/privet/printer/submitdoc", ]
進階列印 - 用戶端應先在印表機上建立列印工作,方法是在要求中呼叫 /privet/printer/createjob API,並提供有效的 CJT 工作單。印表機「必須」將列印票證儲存在記憶體中,並將 job_id 回傳給用戶端。接著,用戶端會呼叫 /printer/submitdoc API,並指定先前收到的 job_id。屆時印表機就會開始列印。用戶端會呼叫 /privet/printer/jobstate API,輪詢印表機的列印工作狀態。
在多重用戶端環境中,無法保證如何呼叫此 API。一個用戶端有可能在另一個用戶端的/createjob->/submitdoc 呼叫之間呼叫 /createjob。為避免可能發生的死結並提升可用性,建議在印表機上保留少量待處理的列印工作佇列 (至少 3 到 5 個):
- /createjob 會使用佇列中的第一個可用位置。
- 工作生命週期 (在佇列中) 至少為 5 分鐘。
- 如果佇列已滿,系統會移除最舊的非列印工作,並將新工作放在該處。
- 如果裝置目前正在列印工作 (簡單或進階列印),/submitdoc 應會傳回忙碌狀態,並建議逾時時間,以便重試這項列印工作。
- 如果 /submitdoc 參照的工作已從佇列中移除 (因取代或逾時),印表機應傳回 invalid_print_job 錯誤,且用戶端會從 /createjob 步驟重試程序。用戶端必須等待隨機逾時期間 (最多 5 秒),才能重試。
如果記憶體限制導致裝置無法儲存多個待處理工作,則佇列長度可能為 1 個列印工作。但仍應遵循上述相同通訊協定。工作完成或因錯誤而失敗後,印表機應至少儲存工作狀態資訊 5 分鐘。儲存已完成工作狀態的佇列大小應至少為 10。如果需要儲存更多工作狀態,系統可能會在 5 分鐘逾時前,從佇列中移除最舊的工作狀態。
注意:目前用戶端會輪詢工作狀態。日後,我們可能會要求印表機在「任何」列印工作狀態變更時,傳送 TXT DNS 通知。
5.1. /privet/printer/createjob API
/privet/printer/createjob API 為選用項目 (請參閱上方的「簡易列印」)。這是 HTTP POST 要求。/privet/printer/createjob API 必須檢查有效的「X-Privet-Token」標頭。 裝置「必須」在「/privet/printer/createjob」網址上實作這項 API:
POST /privet/printer/createjob HTTP/1.1
5.1.1. 輸入
/privet/printer/createjob API 的網址中沒有輸入參數。要求主體應包含 CJT 格式的列印工作單資料。5.1.2. 回攻員
/privet/printer/createjob API 會傳回下列資料:值名稱 | 值類型 | 說明 |
---|---|---|
job_id | 字串 | 新建立的列印工作 ID。 |
expires_in | int | 這項列印工作的有效秒數。 |
範例:
{ "job_id": "123", "expires_in": 600 }
5.1.3. 錯誤
/privet/printer/createjob API 可能會傳回下列錯誤 (詳情請參閱「錯誤」一節):錯誤 | 說明 |
---|---|
invalid_ticket | 提交的列印票證無效。 |
printer_busy | 印表機忙碌中,目前無法處理 /createjob。逾時後重試。 |
printer_error | 印表機處於錯誤狀態,需要使用者互動才能修正。 說明應包含更詳細的解釋 (例如「紙張在紙匣 1 中卡住」)。 |
invalid_x_privet_token | 要求中的 X-Privet-Token 無效或空白。 |
如果裝置未公開 /privet/printer/createjob,則必須傳回 HTTP 404 錯誤。如果缺少 X-Privet-Token 標頭,裝置必須傳回 HTTP 400 錯誤。
5.2. /privet/printer/submitdoc API
如要在本機網路 (離線或重新發布至雲端列印) 上實作列印作業,就必須使用 /privet/printer/submitdoc API。這是 HTTP POST 要求。/privet/printer/submitdoc API 必須檢查有效的「X-Privet-Token」標頭。裝置必須在「/privet/printer/submitdoc」網址上實作這項 API:POST /privet/printer/submitdoc HTTP/1.1
如果印表機無法將所有資料保留在內部緩衝區,則應使用 TCP 機制減緩資料傳輸速度,直到印表機列印部分文件,使部分緩衝區再次可用為止。(舉例來說,印表機可能會在 TCP 層設定 windowsize=0,導致用戶端等待)。
將文件提交至印表機可能需要相當長的時間。列印進行中時,用戶端應能檢查印表機和工作的狀態 (進階列印)。為此,印表機在處理 /privet/printer/submitdoc API 呼叫時,必須允許用戶端呼叫/privet/info 和 /privet/printer/jobstate API。建議所有用戶端啟動新執行緒來執行 /privet/printer/submitdoc API 呼叫,這樣主執行緒就能使用 /privet/info 和 /privet/printer/jobstate API 檢查印表機和列印工作狀態。
注意:完成或中止本機列印工作後,強烈建議 (且在日後的規格版本中會強制執行) 向 /cloudprint/submit 介面回報工作的最終狀態,以利會計和提升使用者體驗。「printerid」、「title」、「contentType」和「final_semantic_state」參數 (採用 PrintJobState 格式) 為必填參數,而「tag」參數 (重複參數) 和「ticket」參數 (採用 CloudJobTicket 格式的工作票證) 則為選填參數。請注意,提供的 PrintJobState 必須是最終狀態,也就是說,其類型必須為 DONE 或 ABORTED,且如果是 ABORTED,則必須提供原因 (詳情請參閱「JobState」)。另請注意,規格中未提及使用 /cloudprint/submit 介面回報本機列印工作,因為該節旨在說明介面的主要用途:提交列印工作,並在「content」參數中提供要列印的文件。
5.2.1. 輸入
/privet/printer/submitdoc API 具有下列輸入參數:名稱 | 值 |
---|---|
job_id | (選用) 列印工作 ID。簡單的列印案例可省略此步驟 (請參閱上文)。必須與印表機傳回的 ID 相符。 |
user_name | (選用) 使用者可判讀的使用者名稱。這並非最終結果,僅供列印工作註解使用。如果工作重新發布至雲端列印服務,這個字串應附加至雲端列印工作。 |
client_name | (選用) 提出這項要求的用戶端應用程式名稱。僅供查看,如果工作重新發布至雲端列印服務,這個字串應附加至雲端列印工作。 |
job_name | (選用) 要記錄的列印工作名稱。如果工作重新發布至雲端列印服務,這個字串應附加至雲端列印工作。 |
離線 | (選用) 只能是「offline=1」。在這種情況下,印表機應只嘗試離線列印 (不會重新發布至雲端列印伺服器)。 |
要求主體應包含可供列印的有效文件。「Content-Length」應包含要求的正確長度。「Content-Type」標頭應設為文件 MIME 類型,並符合 CDD 中的其中一種類型 (除非 CDD 指定「*/*」)。
強烈建議客戶在提出這項要求時,提供有效的使用者名稱 (或電子郵件地址)、客戶名稱和工作名稱。這些欄位只會用於使用者介面,以提升使用者體驗。
5.2.2. 回攻員
/privet/printer/submitdoc API 會傳回下列資料:值名稱 | 值類型 | 說明 |
---|---|---|
job_id | 字串 | 新建立的列印工作 ID (簡單列印),或要求中指定的工作 ID (進階列印)。 |
expires_in | int | 這項列印工作的有效秒數。 |
job_type | 字串 | 提交文件的內容類型。 |
job_size | int 64 位元 | 列印資料的大小 (以位元組為單位)。 |
job_name | 字串 | (選用) 與輸入內容中的工作名稱相同 (如有)。 |
範例:
{ "job_id": "123", "expires_in": 500, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
5.2.3. 錯誤
/privet/printer/submitdoc API 可能會傳回下列錯誤 (詳情請參閱「錯誤」一節):錯誤 | 說明 |
---|---|
invalid_print_job | 要求中指定的工作 ID 無效/已過期。逾時後重試。 |
invalid_document_type | 印表機不支援文件 MIME 類型。 |
invalid_document | 提交的文件無效。 |
document_too_large | 文件超過允許的大小上限。 |
printer_busy | 印表機忙碌中,目前無法處理文件。逾時後重試。 |
printer_error | 印表機處於錯誤狀態,需要使用者互動才能修正。 說明應包含更詳細的解釋 (例如「紙張在紙匣 1 中卡住」)。 |
invalid_params | 要求中指定的參數無效。(為確保日後相容性,請安全地忽略不明參數) |
user_cancel | 使用者從裝置明確取消列印程序。 |
server_error | 無法將文件發布至雲端列印。 |
invalid_x_privet_token | 要求中的 X-Privet-Token 無效或空白。 |
如果裝置未公開 /privet/printer/submitdoc,則必須傳回 HTTP 404 錯誤。如果缺少 X-Privet-Token 標頭,裝置必須傳回 HTTP 400 錯誤。
注意:/privet/printer/submitdoc API 可能需要在印表機端進行特殊處理 (因為附加的酬載較大)。在某些情況下 (取決於印表機 HTTP 伺服器實作和平台),印表機可能會在傳回 HTTP 錯誤前關閉通訊端。在其他情況下,印表機可能會傳回 503 錯誤 (而非 Privet 錯誤)。印表機應盡可能傳回 Privet。不過,實作 Privet 規格的每個用戶端「應該」都能處理 /privet/printer/submitdoc API 的通訊端關閉 (無 HTTP 錯誤) 和 503 HTTP 錯誤案例。在本例中,用戶端應將其視為 Privet「printer_busy」錯誤,並將「timeout」設為 15 秒。為避免無限重試,用戶端可能會在嘗試合理次數 (例如 3 次) 後停止重試。
5.3. /privet/printer/jobstate API
/privet/printer/jobstate API 為選用項目 (請參閱上文的「簡易列印」)。這是 HTTP GET 要求。 /privet/printer/jobstate API 必須檢查「X-Privet-Token」標頭是否有效。裝置「必須」在「/privet/printer/jobstate」網址上實作這項 API:GET /privet/printer/jobstate HTTP/1.1
5.3.1. 輸入
/privet/printer/jobstate API 具有下列輸入參數:名稱 | 值 |
---|---|
job_id | 要傳回狀態的列印工作 ID。 |
5.3.2. 回攻員
/privet/printer/jobstate API 會傳回下列資料:值名稱 | 值類型 | 說明 |
---|---|---|
job_id | 字串 | 列印工作 ID,用於提供狀態資訊。 |
州 | 字串 | 草稿 - 裝置上已建立列印工作 (尚未收到任何 /privet/printer/submitdoc 呼叫)。 已加入佇列:已收到並加入佇列,但尚未開始列印。 in_progress - 列印工作正在進行中。 已停止 - 列印工作已暫停,但可以手動或自動重新啟動。 done - 列印工作已完成。 已取消 - 列印工作失敗。 |
說明 | 字串 | (選用) 使用者可理解的列印工作狀態說明。如果 state< 為 stopped 或 aborted,則應納入額外資訊。semantic_state 欄位通常會為用戶端提供更優質且更有意義的說明。 |
expires_in | int | 這項列印工作的有效秒數。 |
job_type | 字串 | (選用) 提交文件的內容類型。 |
job_size | int 64 位元 | (選用) 列印資料的大小 (以位元組為單位)。 |
job_name | 字串 | (選用) 與輸入內容中的工作名稱相同 (如有)。 |
server_job_id | 字串 | (選用) 伺服器傳回的工作 ID (如果工作已發布至雲端列印服務)。離線列印時會省略這項資訊。 |
semantic_state | JSON | (選用) 採用 PrintJobState 格式的工作語意狀態。 |
範例 (透過雲端列印回報列印作業):
{ "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" }
示例 (離線列印錯誤):
{ "job_id": "123", "state": "stopped", "description": "Out of paper", "expires_in": 100, "job_type": "application/pdf", "job_size": 123456, "job_name": "My PDF document" }
範例 (使用者中止列印工作):
{ "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 } }
例如,紙張用盡而停止列印工作。請注意裝置狀態的參照。用戶端需要呼叫 /privet/info API,才能取得裝置狀態的詳細資料:
{ "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. 錯誤
/privet/printer/jobstate API 可能會傳回下列錯誤 (詳情請參閱「錯誤」一節):錯誤 | 說明 |
---|---|
invalid_print_job | 要求中指定的工作 ID 無效/已過期。 |
server_error | 無法取得列印工作狀態 (針對發布至雲端列印的列印工作)。 |
invalid_x_privet_token | 要求中的 X-Privet-Token 無效或空白。 |
如果裝置未公開 /privet/printer/jobstate,則必須傳回 HTTP 404 錯誤。如果缺少 X-Privet-Token 標頭,裝置必須傳回 HTTP 400 錯誤。
6. 附錄
6.1. 預設行為和設定
本節將說明所有 Privet 相容裝置的預設行為。- 立即可用的裝置應僅支援 /privet/info 和 /privet/register API。應停用所有其他 API (例如 /privet/accesstoken、本機列印)。
- 註冊時必須與裝置進行實體互動。
- 使用者必須在裝置上採取實際行動 (例如按下按鈕),確認自己有權存取裝置。
- 使用者執行上述動作後,印表機應傳送 /cloudprint/register 要求。在採取行動後,才應傳送這項要求 (請參閱序號圖 1)。
- 如果裝置正在處理 /privet/register 要求 (例如等待上述動作),則必須拒絕所有其他 /privet/register 要求。在這種情況下,裝置「必須」傳回 device_busy 錯誤。
- 如果裝置在 60 秒內未收到上述實體動作,應會對任何 /register 要求逾時。在這種情況下,裝置「必須」傳回 confirmation_timeout 錯誤。
- 選用:建議使用,但非必要。下列項目可提升使用者體驗:
- 印表機可能會閃爍燈號或顯示畫面,表示使用者需要採取行動來確認註冊。
- 印表機螢幕上可能會顯示「正在為使用者『abc@def.com』向 Google 雲端列印服務註冊 - 按下『確定』繼續」,其中 abc@def.com 是 /register API 呼叫中的使用者參數。這樣一來,使用者就能更清楚瞭解:
- 確認的是他們的註冊要求
- 如果對方並未觸發要求,會發生什麼情況?
- 除了在印表機上進行實體操作來確認 (例如「按一下『確定』按鈕」),印表機也可能會提供取消要求的按鈕 (例如「按一下『取消』拒絕」。這樣一來,如果使用者並未觸發註冊要求,就能在 60 秒逾時前取消要求。在這種情況下,裝置「必須」傳回 user_cancel 錯誤。
- 擁有權轉移:
- 裝置可能已從雲端服務中明確刪除。
- 如果裝置收到成功訊息,但 /cloudprint/printer (適用於 GCP) 呼叫未傳回裝置說明,裝置就必須還原為預設 (開箱即用) 模式。
- 如果裝置憑證無法再運作 (明確是因為伺服器傳回「無效憑證」回應),裝置「必須」還原為預設 (開箱即用) 模式。
- 本機恢復原廠設定「必須」清除裝置憑證,並將裝置設為預設狀態。
- 選用:裝置可能會提供選單項目,用來清除憑證並設為預設模式。
- 支援 XMPP 通知的裝置「必須」具備 Ping 伺服器的功能。伺服器必須能透過「local_settings」控制 Ping 逾時。
- 裝置每天最多會明確對伺服器執行一次 Ping 作業 (除了 XMPP Ping 作業外,還會對 GCP 的 /cloudprint/printer API 執行 Ping 作業),確保裝置與伺服器保持同步。建議在 24 到 32 小時內隨機檢查。
- 選用:如果是雲端列印裝置,建議 (但非必要) 提供手動方式 (按鈕),讓使用者從裝置啟動新列印工作檢查。部分印表機已具備這項功能。
- (選用步驟) 企業印表機可能提供完全停用本機探索的選項。在這種情況下,裝置必須更新伺服器上的這些本機設定。新的本機設定必須為空白 (將「local_discovery」設定為「false」,表示可以從 GCP 服務重新啟用)。
6.1.2 預設註冊圖

6.2. XSSI 和 XSRF 攻擊與防範
本節將說明裝置可能遭受的 XSSI 和 XSRF 攻擊,以及如何防範這類攻擊 (包括權杖產生技術)。詳情請參閱: http://googleonlinesecurity.blogspot.com/2011/05/website-security-for-webmasters.html
一般來說,如果網站使用 Cookie 驗證機制,就可能遭受 XSSI 和 XSRF 攻擊。雖然 Google 不會透過雲端列印服務使用 Cookie,但這類攻擊仍有可能發生。根據設計,區域網路存取權會隱含信任要求。
6.2.1. XSSI
惡意網站可能會猜測與 Privet 相容裝置的 IP 位址和通訊埠號碼,並嘗試使用 <script> 標記內的「src=<api name>」呼叫 Privet API:<script type="text/javascript" src="http://192.168.1.42:8080/privet/info"></script>
為防範這類攻擊,所有 Privet API 呼叫都必須在要求中加入「X-Privet-Token」標頭。「src=<api>」指令碼標記無法新增標頭,可有效防範這類攻擊。
6.2.2. XSRF
http://en.wikipedia.org/wiki/Cross-site_request_forgery惡意網站可能會猜測與 Privet 相容裝置的 IP 位址和通訊埠號碼,並嘗試使用 <iframe>、表單或其他跨網站載入機制呼叫 Privet API。攻擊者無法存取要求結果,但如果要求會執行動作 (例如列印),攻擊者就能觸發該動作。
為防範這類攻擊,我們需要下列防護措施:
- 將 /privet/info API 開放給 XSRF
- /privet/info API 不得在裝置上執行任何動作
- 使用 /privet/info API 接收 x-privet-token
- 所有其他 API 都必須檢查「X-Privet-Token」標頭中是否有有效的 x-privet-token。
- x-privet-token 的效期應只有 24 小時。
即使攻擊者能夠執行 /privet/info API,也無法從回應中讀取 x-privet-token,因此無法呼叫任何其他 API。
強烈建議使用下列演算法產生 XSRF 權杖:
XSRF_token = base64( SHA1(device_secret + DELIMITER + issue_timecounter) + DELIMITER + issue_timecounter )
產生 XSRF 權杖的元素:
- DELIMITER 是特殊字元,通常為「:」
- issue_timecounter 是自某個事件 (時間戳記的紀元) 或裝置啟動時間 (適用於 CPU 計數器) 以來的秒數。裝置啟動並執行時,issue_timecounter 會持續增加 (請參閱下方的權杖驗證)。
- SHA1 - 使用 SHA1 演算法的雜湊函式
- base64 - base64 編碼
- device_secret - 裝置專屬密鑰。每次重新啟動時,裝置密鑰都必須更新。
建議產生裝置密鑰的方式:
- 每次重新啟動時產生新的 UUID
- 每次重新啟動時產生 64 位元的隨機數字
裝置不必儲存發行的所有 XSRF 權杖。裝置需要驗證 XSRF 權杖是否有效時,應先對權杖進行 Base64 解碼,從後半部 (明文) 取得 issue_timecounter,然後嘗試產生 device_secret + DELIMITER + issue_timecounter 的 SHA1 雜湊,其中 issue_timecounter 來自權杖。如果新產生的 SHA1 與權杖中的 SHA1 相符,裝置現在必須檢查 issue_timecounter 是否在目前時間計數器的效期內 (24 小時)。為此,裝置會取得目前的時間計數器 (例如 CPU 計數器),並從中減去 issue_timecounter。結果必須是自核發權杖以來經過的秒數。
重要事項:建議您採用這種方式實作 XSRF 保護機制。Privet 規格的用戶端不應嘗試瞭解 XSRF 權杖,而是應將其視為黑箱。圖 6.2.3 說明實作 X-Privet-Token 和驗證一般要求的建議方式。
6.2.3 X-Privet 權杖產生和驗證流程圖

6.3. 工作流程圖
本節將說明不同情況下的工作流程。6.3.1. 印表機開箱即用工作流程

6.3.2. 已註冊印表機啟動

6.3.3 XMPP 通知處理工作流程

6.3.4. 檢查印表機設定工作流程
