feat(desktop): sign every Windows release artifact (#1548)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-10 23:22:19 +02:00
1 parent 873c203b5d
commit 6e66c92dca
89 files changed
+2408 -2740

No files matched your search

@@ -4,13 +4,7 @@ import {Readable} from 'node:stream';
import {
DesktopChecksumRedirectParam,
DesktopRedirectParam,
DesktopSourceChecksumResponse,
DesktopTestBuildQuery,
DesktopVariantChecksumRedirectParam,
DesktopVariantRedirectParam,
DesktopVariantVersionedChecksumRedirectParam,
DesktopVariantVersionedRedirectParam,
DesktopVariantVersionsParam,
DesktopVersionedChecksumRedirectParam,
DesktopVersionedRedirectParam,
DesktopVersionsParam,
@@ -136,239 +130,6 @@ function checksumFileResponse(ctx: Context<HonoEnv>, checksum: DesktopChecksumFi
}
export function DownloadController(routes: Hono<HonoEnv>): void {
routes.on(
['GET', 'HEAD'],
`${DESKTOP_REDIRECT_PREFIX}/source/latest`,
OpenAPI({
operationId: 'download_latest_desktop_source',
summary: 'Download latest desktop source tarball',
responseSchema: null,
statusCode: 200,
security: [],
tags: ['Downloads'],
description: 'Streams the latest published Fluxer desktop source tarball from the downloads bucket.',
}),
async (ctx) => {
const downloadService = ctx.get('downloadService');
const info = await downloadService.getLatestDesktopSourceInfo({baseUrl: Config.endpoints.apiClient});
if (!info) {
return ctx.text('Not Found', 404);
}
return streamArtifactResponse(ctx, downloadService, info.key, 'public, max-age=300', info.filename);
},
);
routes.get(
`${DESKTOP_REDIRECT_PREFIX}/source/latest/sha256`,
OpenAPI({
operationId: 'get_latest_desktop_source_sha256',
summary: 'Get latest desktop source tarball checksum',
responseSchema: DesktopSourceChecksumResponse,
statusCode: 200,
security: [],
tags: ['Downloads'],
description: 'Returns the SHA-256 checksum and metadata for the latest published Fluxer desktop source tarball.',
}),
async (ctx) => {
const info = await ctx.get('downloadService').getLatestDesktopSourceInfo({baseUrl: Config.endpoints.apiClient});
if (!info) {
return ctx.text('Not Found', 404);
}
return ctx.json(
{
sha256: info.sha256,
filename: info.filename,
url: info.url,
...(info.commit ? {commit: info.commit} : {}),
...(info.desktop_version ? {desktop_version: info.desktop_version} : {}),
...(info.desktop_version_source ? {desktop_version_source: info.desktop_version_source} : {}),
published_at: info.published_at,
...(info.size === undefined ? {} : {size: info.size}),
},
200,
{'Cache-Control': 'public, max-age=300'},
);
},
);
routes.get(
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/:variant/latest`,
Validator('param', DesktopVariantVersionsParam),
Validator('query', DesktopTestBuildQuery),
OpenAPI({
operationId: 'get_latest_desktop_variant_version',
summary: 'Get latest desktop variant version',
responseSchema: VersionInfoResponse,
statusCode: 200,
security: [],
tags: ['Downloads'],
description:
'Returns metadata for the latest desktop version in a build variant, including download URLs and SHA-256 checksums for all available formats.',
}),
async (ctx) => {
const {channel, plat, arch, variant} = ctx.req.valid('param');
const {test} = ctx.req.valid('query');
const result = await ctx.get('downloadService').getLatestDesktopVersion({
channel,
plat,
arch,
variant,
baseUrl: Config.endpoints.apiClient,
test,
});
if (!result) {
return ctx.text('Not Found', 404);
}
return ctx.json(result, 200, {
'Cache-Control': 'public, max-age=300',
});
},
);
routes.on(
['GET', 'HEAD'],
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/:variant/latest/:format{[a-z_]+\\.sha256}`,
Validator('param', DesktopVariantChecksumRedirectParam),
Validator('query', DesktopTestBuildQuery),
OpenAPI({
operationId: 'download_latest_desktop_variant_checksum',
summary: 'Download latest desktop variant checksum',
responseSchema: null,
statusCode: 200,
security: [],
tags: ['Downloads'],
description:
'Returns a plain text SHA-256 checksum file for the latest available desktop application version in a build variant.',
}),
async (ctx) => {
const {channel, plat, arch, variant, format} = ctx.req.valid('param');
const {test} = ctx.req.valid('query');
const checksum = await ctx
.get('downloadService')
.resolveLatestDesktopChecksumFile({channel, plat, arch, variant, format, test});
if (!checksum) {
return ctx.text('Not Found', 404);
}
return checksumFileResponse(ctx, checksum, 'no-store');
},
);
routes.on(
['GET', 'HEAD'],
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/:variant/latest/:format`,
Validator('param', DesktopVariantRedirectParam),
Validator('query', DesktopTestBuildQuery),
OpenAPI({
operationId: 'download_latest_desktop_variant',
summary: 'Download latest desktop variant',
responseSchema: null,
statusCode: 200,
security: [],
tags: ['Downloads'],
description:
'Streams the latest available desktop application version for the specified platform, architecture, and build variant.',
}),
async (ctx) => {
const {channel, plat, arch, variant, format} = ctx.req.valid('param');
const {test} = ctx.req.valid('query');
const downloadService = ctx.get('downloadService');
const key = await downloadService.resolveLatestDesktopKey({channel, plat, arch, variant, format, test});
if (!key) {
return ctx.text('Not Found', 404);
}
return streamArtifactResponse(ctx, downloadService, key, 'no-store');
},
);
routes.get(
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/:variant/versions`,
Validator('param', DesktopVariantVersionsParam),
Validator('query', DesktopVersionsQuery),
OpenAPI({
operationId: 'list_desktop_variant_versions',
summary: 'List desktop variant versions',
responseSchema: DesktopVersionsResponse,
statusCode: 200,
security: [],
tags: ['Downloads'],
description:
'Lists available desktop versions with pagination for the specified platform, architecture, and variant.',
}),
async (ctx) => {
const {channel, plat, arch, variant} = ctx.req.valid('param');
const {limit, before, after, test} = ctx.req.valid('query');
const {versions, hasMore} = await ctx.get('downloadService').listDesktopVersions({
channel,
plat,
arch,
variant,
limit,
before,
after,
baseUrl: Config.endpoints.apiClient,
test,
});
return ctx.json({versions, has_more: hasMore}, 200, {
'Cache-Control': 'public, max-age=300',
});
},
);
routes.on(
['GET', 'HEAD'],
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/:variant/:version/:format{[a-z_]+\\.sha256}`,
Validator('param', DesktopVariantVersionedChecksumRedirectParam),
Validator('query', DesktopTestBuildQuery),
OpenAPI({
operationId: 'download_desktop_variant_version_checksum',
summary: 'Download desktop variant version checksum',
responseSchema: null,
statusCode: 200,
security: [],
tags: ['Downloads'],
description:
'Returns a plain text SHA-256 checksum file for a specific desktop application version in a build variant.',
}),
async (ctx) => {
const {channel, plat, arch, variant, version, format} = ctx.req.valid('param');
const {test} = ctx.req.valid('query');
const checksum = await ctx
.get('downloadService')
.resolveVersionedDesktopChecksumFile({channel, plat, arch, variant, version, format, test});
if (!checksum) {
return ctx.text('Not Found', 404);
}
return checksumFileResponse(ctx, checksum, 'public, max-age=86400');
},
);
routes.on(
['GET', 'HEAD'],
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/:variant/:version/:format`,
Validator('param', DesktopVariantVersionedRedirectParam),
Validator('query', DesktopTestBuildQuery),
OpenAPI({
operationId: 'download_desktop_variant_version',
summary: 'Download desktop variant version',
responseSchema: null,
statusCode: 200,
security: [],
tags: ['Downloads'],
description:
'Streams a specific desktop application version for the given platform, architecture, and build variant.',
}),
async (ctx) => {
const {channel, plat, arch, variant, version, format} = ctx.req.valid('param');
const {test} = ctx.req.valid('query');
const downloadService = ctx.get('downloadService');
const key = await downloadService.resolveVersionedDesktopKey({
channel,
plat,
arch,
variant,
version,
format,
test,
});
if (!key) {
return ctx.text('Not Found', 404);
}
return streamArtifactResponse(ctx, downloadService, key, 'public, max-age=86400');
},
);
routes.get(
`${DESKTOP_REDIRECT_PREFIX}/:channel/:plat/:arch/latest`,
Validator('param', DesktopVersionsParam),
+5 -181
View File
@@ -8,7 +8,6 @@ import type {
DesktopChannel,
DesktopFormat,
DesktopPlatform,
DesktopVariant,
} from '@fluxer/schema/src/domains/download/DownloadSchemas';
import {Config} from '../Config';
import type {IStorageService} from '../infrastructure/IStorageService';
@@ -46,7 +45,6 @@ function isUnsatisfiableRangeError(error: unknown): boolean {
}
const DESKTOP_BUCKET_PREFIX = 'desktop';
const DESKTOP_TEST_BUCKET_PREFIX = 'desktop-test';
const DESKTOP_SOURCE_MANIFEST_KEY = `${DESKTOP_BUCKET_PREFIX}/source/latest.json`;
const DEFAULT_API_CLIENT_BASE_URL = 'https://api.fluxer.app';
function desktopBucketPrefix(test?: boolean): string {
@@ -57,14 +55,9 @@ function desktopArtifactPrefix(params: {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
test?: boolean;
}): string | null {
if (params.variant && params.plat !== 'win32') {
return null;
}
const base = `${desktopBucketPrefix(params.test)}/${params.channel}/${params.plat}/${params.arch}`;
return params.variant ? `${base}/${params.variant}` : base;
return `${desktopBucketPrefix(params.test)}/${params.channel}/${params.plat}/${params.arch}`;
}
type DesktopManifestFileEntry =
@@ -77,7 +70,6 @@ type DesktopManifest = {
channel: DesktopChannel;
platform: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant | null;
version: string;
pub_date: string;
minimum_system_version?: string | null;
@@ -111,7 +103,6 @@ type VersionFile = {
};
type VersionInfo = {
version: string;
variant?: DesktopVariant | null;
pub_date: string;
minimum_system_version?: string | null;
files: Record<string, VersionFile>;
@@ -121,26 +112,6 @@ export type DesktopChecksumFile = {
sha256: string;
body: string;
};
type DesktopSourceManifest = {
filename: string;
key: string;
sha256: string;
commit?: string;
desktop_version?: string;
desktop_version_source?: {
channel: DesktopChannel;
platform: DesktopPlatform;
arch: DesktopArch;
key: string;
pub_date: string;
};
published_at: string;
size?: number;
};
type DesktopSourceInfo = DesktopSourceManifest & {
url: string;
};
function isDesktopManifestFileEntry(value: unknown): value is DesktopManifestFileEntry {
if (typeof value === 'string') {
return true;
@@ -154,7 +125,6 @@ function isDesktopManifest(value: unknown): value is DesktopManifest {
(value.channel === 'stable' || value.channel === 'canary') &&
(value.platform === 'win32' || value.platform === 'darwin' || value.platform === 'linux') &&
(value.arch === 'x64' || value.arch === 'arm64') &&
(value.variant === undefined || value.variant === null || value.variant === 'windows-game-capture') &&
typeof value.version === 'string' &&
typeof value.pub_date === 'string' &&
(value.minimum_system_version === undefined ||
@@ -164,37 +134,11 @@ function isDesktopManifest(value: unknown): value is DesktopManifest {
);
}
function isDesktopSourceManifest(value: unknown): value is DesktopSourceManifest {
if (!isJsonRecord(value)) return false;
return (
typeof value.filename === 'string' &&
typeof value.key === 'string' &&
typeof value.sha256 === 'string' &&
(value.commit === undefined || typeof value.commit === 'string') &&
(value.desktop_version === undefined || typeof value.desktop_version === 'string') &&
(value.desktop_version_source === undefined || isDesktopVersionSource(value.desktop_version_source)) &&
typeof value.published_at === 'string' &&
(value.size === undefined || typeof value.size === 'number')
);
}
function isDesktopVersionSource(value: unknown): value is DesktopSourceManifest['desktop_version_source'] {
if (!isJsonRecord(value)) return false;
return (
(value.channel === 'stable' || value.channel === 'canary') &&
(value.platform === 'win32' || value.platform === 'darwin' || value.platform === 'linux') &&
(value.arch === 'x64' || value.arch === 'arm64') &&
typeof value.key === 'string' &&
typeof value.pub_date === 'string'
);
}
interface LatestFilenameLookupParams {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
format: DesktopFormat;
variant?: DesktopVariant;
test?: boolean;
}
@@ -205,42 +149,11 @@ interface ManifestFilenameResolutionParams extends LatestFilenameLookupParams {
export class DownloadService {
constructor(private readonly storageService: IStorageService) {}
async getLatestDesktopSourceInfo(params: {baseUrl?: string} = {}): Promise<DesktopSourceInfo | null> {
const manifest = await this.readDesktopSourceManifest();
if (!manifest) {
return null;
}
let size = manifest.size;
try {
const metadata = await this.storageService.getObjectMetadata(Config.s3.buckets.downloads, manifest.key);
if (!metadata) {
return null;
}
size = size ?? metadata.contentLength;
} catch (error) {
if (error instanceof S3ServiceException && (error.name === 'NoSuchKey' || error.name === 'NotFound')) {
return null;
}
throw error;
}
return {
...manifest,
...(size === undefined ? {} : {size}),
url: `${this.buildBaseUrl(params.baseUrl)}${DESKTOP_REDIRECT_PREFIX}/source/latest`,
};
}
async resolveLatestDesktopSourceKey(): Promise<string | null> {
const info = await this.getLatestDesktopSourceInfo();
return info?.key ?? null;
}
async resolveLatestDesktopKey(params: {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
format: DesktopFormat;
variant?: DesktopVariant;
test?: boolean;
}): Promise<string | null> {
const prefix = desktopArtifactPrefix(params);
@@ -267,7 +180,6 @@ export class DownloadService {
arch: params.arch,
format: params.format,
filename,
variant: params.variant,
test: params.test,
});
if (!resolvedFilename) {
@@ -278,7 +190,6 @@ export class DownloadService {
plat: params.plat,
arch: params.arch,
filename: resolvedFilename,
variant: params.variant,
test: params.test,
});
} catch (error) {
@@ -293,7 +204,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
baseUrl?: string;
test?: boolean;
}): Promise<VersionInfo | null> {
@@ -324,7 +234,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
limit: number;
before?: string | null;
after?: string | null;
@@ -457,7 +366,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
version,
format,
baseUrl: params.baseUrl,
@@ -469,7 +377,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
version,
format,
baseUrl: params.baseUrl,
@@ -480,7 +387,6 @@ export class DownloadService {
}
versions.push({
version,
...(params.variant ? {variant: params.variant} : {}),
pub_date: entry.pub_date.toISOString(),
files,
});
@@ -498,7 +404,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
version: string;
format: DesktopFormat;
test?: boolean;
@@ -544,7 +449,6 @@ export class DownloadService {
plat: DesktopPlatform;
arch: DesktopArch;
format: DesktopFormat;
variant?: DesktopVariant;
test?: boolean;
}): Promise<DesktopChecksumFile | null> {
const version = await this.getLatestDesktopVersion(params);
@@ -564,7 +468,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
version: string;
format: DesktopFormat;
test?: boolean;
@@ -592,11 +495,9 @@ export class DownloadService {
return null;
}
const rewrittenKey = params.test ? this.rewriteToTestBucketKey(key) : key;
const keysToTry = [rewrittenKey];
const normalizedKey = this.normalizePlatformArchKey(rewrittenKey);
if (normalizedKey) {
keysToTry.push(normalizedKey);
}
const candidateKeys = [rewrittenKey, normalizedKey];
const keysToTry = Array.from(new Set(candidateKeys.filter((candidate): candidate is string => candidate !== null)));
for (const candidateKey of keysToTry) {
try {
const metadata = await this.storageService.getObjectMetadata(Config.s3.buckets.downloads, candidateKey);
@@ -669,14 +570,12 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
version: string;
format: DesktopFormat;
baseUrl?: string;
test?: boolean;
}): string {
const variantSegment = params.variant ? `/${params.variant}` : '';
const url = `${this.buildBaseUrl(params.baseUrl)}${DOWNLOAD_PREFIX}/desktop/${params.channel}/${params.plat}/${params.arch}${variantSegment}/${params.version}/${params.format}`;
const url = `${this.buildBaseUrl(params.baseUrl)}${DOWNLOAD_PREFIX}/desktop/${params.channel}/${params.plat}/${params.arch}/${params.version}/${params.format}`;
return params.test ? `${url}?test=1` : url;
}
@@ -684,14 +583,12 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
version: string;
format: DesktopFormat;
baseUrl?: string;
test?: boolean;
}): string {
const variantSegment = params.variant ? `/${params.variant}` : '';
const url = `${this.buildBaseUrl(params.baseUrl)}${DOWNLOAD_PREFIX}/desktop/${params.channel}/${params.plat}/${params.arch}${variantSegment}/${params.version}/${params.format}.sha256`;
const url = `${this.buildBaseUrl(params.baseUrl)}${DOWNLOAD_PREFIX}/desktop/${params.channel}/${params.plat}/${params.arch}/${params.version}/${params.format}.sha256`;
return params.test ? `${url}?test=1` : url;
}
@@ -722,65 +619,10 @@ export class DownloadService {
return parseJsonUnknown(text);
}
private async readDesktopSourceManifest(): Promise<DesktopSourceManifest | null> {
let manifest: unknown | null;
try {
manifest = await this.readJsonObjectFromStorage(DESKTOP_SOURCE_MANIFEST_KEY);
} catch (error) {
if (error instanceof S3ServiceException && (error.name === 'NoSuchKey' || error.name === 'NotFound')) {
return null;
}
throw error;
}
if (!isDesktopSourceManifest(manifest)) {
return null;
}
if (
!this.isSafeDesktopSourceKey(manifest.key) ||
!this.isValidSha256(manifest.sha256) ||
(manifest.desktop_version !== undefined && !this.isValidVersion(manifest.desktop_version)) ||
(manifest.desktop_version_source !== undefined &&
!this.isValidDesktopVersionSource(manifest.desktop_version_source)) ||
manifest.filename.trim().length === 0 ||
manifest.published_at.trim().length === 0
) {
return null;
}
return manifest;
}
private isSafeDesktopSourceKey(key: string): boolean {
if (!key.startsWith(`${DESKTOP_BUCKET_PREFIX}/source/by-commit/`)) {
return false;
}
const normalized = posix.normalize(key);
if (normalized !== key || normalized.startsWith('..') || normalized.includes('\0')) {
return false;
}
return key.endsWith('.tar.gz');
}
private isValidSha256(value: string): boolean {
return /^[a-f0-9]{64}$/u.test(value);
}
private isValidVersion(value: string): boolean {
return /^\d+\.\d+\.\d+$/u.test(value);
}
private isValidDesktopVersionSource(source: DesktopSourceManifest['desktop_version_source']): boolean {
if (!source) {
return false;
}
return (
source.channel === 'canary' &&
source.platform === 'linux' &&
source.arch === 'x64' &&
source.key === 'desktop/canary/linux/x64/manifest.json' &&
source.pub_date.trim().length > 0
);
}
private async resolveManifestFilename(params: ManifestFilenameResolutionParams): Promise<string | null> {
const manifestFilename = params.filename.trim();
if (manifestFilename.length === 0) {
@@ -792,7 +634,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
filename: manifestFilename,
test: params.test,
}))
@@ -1038,7 +879,6 @@ export class DownloadService {
plat: params.plat,
arch: params.arch,
filename,
variant: params.variant,
test: params.test,
});
}
@@ -1047,7 +887,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
version: string;
format: DesktopFormat;
test?: boolean;
@@ -1079,7 +918,6 @@ export class DownloadService {
arch: params.arch,
format: params.format,
filename,
variant: params.variant,
test: params.test,
});
if (!resolvedFilename) {
@@ -1090,7 +928,6 @@ export class DownloadService {
plat: params.plat,
arch: params.arch,
filename: resolvedFilename,
variant: params.variant,
test: params.test,
});
} catch (error) {
@@ -1106,7 +943,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
baseUrl?: string;
test?: boolean;
},
@@ -1125,7 +961,6 @@ export class DownloadService {
arch: params.arch,
format,
filename: manifestFilename,
variant: params.variant,
test: params.test,
});
if (!resolvedFilename) {
@@ -1143,7 +978,6 @@ export class DownloadService {
arch: params.arch,
format,
filename: resolvedFilename,
variant: params.variant,
test: params.test,
})
) {
@@ -1156,7 +990,6 @@ export class DownloadService {
entry,
manifestFilename,
resolvedFilename,
variant: params.variant,
test: params.test,
});
files[format] = {
@@ -1164,7 +997,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
version: manifest.version,
format,
baseUrl: params.baseUrl,
@@ -1176,7 +1008,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
version: manifest.version,
format,
baseUrl: params.baseUrl,
@@ -1191,7 +1022,6 @@ export class DownloadService {
const minimumSystemVersion = manifest.minimum_system_version ?? null;
return {
version: manifest.version,
...(params.variant ? {variant: params.variant} : {}),
pub_date: manifest.pub_date,
...(minimumSystemVersion ? {minimum_system_version: minimumSystemVersion} : {}),
files,
@@ -1202,7 +1032,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
baseUrl?: string;
test?: boolean;
}): Promise<VersionInfo | null> {
@@ -1210,7 +1039,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
limit: 1,
baseUrl: params.baseUrl,
test: params.test,
@@ -1222,7 +1050,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
entry: DesktopManifestFileEntry;
manifestFilename: string;
resolvedFilename: string;
@@ -1238,7 +1065,6 @@ export class DownloadService {
channel: params.channel,
plat: params.plat,
arch: params.arch,
variant: params.variant,
filename: params.resolvedFilename,
test: params.test,
});
@@ -1270,7 +1096,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
filename: string;
test?: boolean;
}): Promise<boolean> {
@@ -1293,7 +1118,6 @@ export class DownloadService {
channel: DesktopChannel;
plat: DesktopPlatform;
arch: DesktopArch;
variant?: DesktopVariant;
filename: string;
test?: boolean;
}): string | null {