— what a site admin copies to the other site. */ final class ConnectionString { private const PREFIX = 'relay1.'; public static function encode(string $site_url, string $key_id, string $secret): string { return self::PREFIX . self::b64(json_encode(['u' => $site_url, 'k' => $key_id, 's' => self::b64($secret)], JSON_UNESCAPED_SLASHES)); } /** @return array{url: string, key_id: string, secret: string} */ public static function decode(string $value): array { $value = trim($value); if (strpos($value, self::PREFIX) !== 0) { throw self::invalid(); } $data = json_decode((string) self::unb64(substr($value, strlen(self::PREFIX))), true); if (!is_array($data) || !is_string($data['u'] ?? null) || !is_string($data['k'] ?? null) || !is_string($data['s'] ?? null)) { throw self::invalid(); } $secret = (string) self::unb64($data['s']); if (!preg_match('#^https?://[^\s/?\#]+#i', $data['u']) || !preg_match('/^[a-z0-9]{12}$/', $data['k']) || strlen($secret) !== 32) { throw self::invalid(); } return ['url' => rtrim($data['u'], '/'), 'key_id' => $data['k'], 'secret' => $secret]; } private static function b64(string $raw): string { return rtrim(strtr(base64_encode($raw), '+/', '-_'), '='); } /** @return string|false */ private static function unb64(string $text) { if (!preg_match('/^[A-Za-z0-9_-]*$/', $text)) { return false; } return base64_decode(strtr($text, '-_', '+/') . str_repeat('=', (4 - strlen($text) % 4) % 4), true); } private static function invalid(): RelayError { return new RelayError('connection.invalid', esc_html__('That is not a valid SiteRelay connection string.', 'siterelay'), esc_html__('Copy the whole string shown when the access key was created on the other site.', 'siterelay')); } }