This commit is contained in:
Manav Rathi
2024-11-26 15:00:42 +05:30
parent ec3f5952b0
commit 7525b0defe
3 changed files with 24 additions and 12 deletions

View File

@@ -5,7 +5,7 @@ import { PairingCode } from "components/PairingCode";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { readCastData, storeCastData } from "services/cast-data";
import { getCastData, register } from "services/pair";
import { getCastPayload, register } from "services/pair";
import { advertiseOnChromecast } from "../services/chromecast-receiver";
export default function Index() {
@@ -35,9 +35,7 @@ export default function Index() {
const pollTick = async () => {
try {
// TODO:
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const data = await getCastData({
const data = await getCastPayload({
publicKey,
privateKey,
pairingCode,

View File

@@ -1,3 +1,5 @@
import type { CastPayload } from "./pair";
export interface CastData {
/** The ID of the callection we are casting. */
collectionID: string;
@@ -12,7 +14,7 @@ export interface CastData {
*
* We will read in back when we start the slideshow.
*/
export const storeCastData = (payload: unknown) => {
export const storeCastData = (payload: CastPayload | undefined) => {
if (!payload || typeof payload != "object")
throw new Error("Unexpected cast data");

View File

@@ -63,7 +63,7 @@ export interface Registration {
* Once the client gets the pairing code (via Chromecast or manual entry),
* they'll let museum know. So in parallel with Phase 2, we perform Phase 3.
*
* Phase 3 - {@link getCastData} in a setInterval.
* Phase 3 - {@link getCastPayload} in a setInterval.
*
* 7. Keep polling museum to ask it if anyone has claimed that code we vended
* out and used that to send us an payload encrypted using our public key.
@@ -78,7 +78,7 @@ export interface Registration {
* At this time we start showing the pairing code on the UI, and start phase 2,
* {@link advertiseCode} to vend out the pairing code to Chromecast connections.
*
* In parallel, we start Phase 3, calling {@link getCastData} in a loop. Once we
* In parallel, we start Phase 3, calling {@link getCastPayload} in a loop. Once we
* get a response, we decrypt it to get the data we need to start the slideshow.
*/
export const register = async (): Promise<Registration> => {
@@ -119,6 +119,18 @@ const registerDevice = async (publicKey: string) => {
.deviceCode;
};
/**
* The structure of the (decrypted) payload that is published (e.g.) by
* `publishCastPayload` on the photos web/desktop app.
*/
const CastPayload = z.object({
castToken: z.string(),
collectionID: z.number(),
collectionKey: z.string(),
});
export type CastPayload = z.infer<typeof CastPayload>;
/**
* Ask museum if anyone has sent a (encrypted) payload corresponding to the
* given pairing code. If so, decrypt it using our private key and return the
@@ -128,13 +140,15 @@ const registerDevice = async (publicKey: string) => {
*
* See: [Note: Pairing protocol].
*/
export const getCastData = async (registration: Registration) => {
export const getCastPayload = async (
registration: Registration,
): Promise<CastPayload | undefined> => {
const { pairingCode, publicKey, privateKey } = registration;
// The client will send us the encrypted payload using our public key that
// we registered with museum.
const encryptedCastData = await getEncryptedCastData(pairingCode);
if (!encryptedCastData) return;
if (!encryptedCastData) return undefined;
// Decrypt it using the private key of the pair and return the plaintext
// payload, which'll be a JSON object containing the data we need to start a
@@ -145,9 +159,7 @@ export const getCastData = async (registration: Registration) => {
privateKey,
);
// TODO:
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return JSON.parse(atob(decryptedCastData));
return CastPayload.parse(JSON.parse(atob(decryptedCastData)));
};
/**