import { filterSafeListByFirmware , filterSafeListByBootloader } from './utils/releases' ; import { fetchFirmware } from './utils/fetch' ; import { getScore } from './utils/score' ; import * as versionUtils from './utils/version' ; import { parseFeatures , parseReleases , Release , Features } from './utils/parse' ; type ParsedFeatures = ReturnType < typeof parseFeatures > ; /**
 * Returns firmware binary after necessary modifications. Should be ok to install.
 */ export const modifyFirmware = ( { fw , features } ) => { if ( features . major_version === 2 ) return fw ; if ( versionUtils . isNewerOrEqual ( [ features . major_version , features . minor_version , features . patch_version ] , [ 1 , 8 , 0 ] ) ) { const fwView = new Uint8Array ( fw ) ; if ( String . fromCharCode ( ... Array . from ( fwView . slice ( 0 , 4 ) ) ) === 'TRZR' && String . fromCharCode ( ... Array . from ( fwView . slice ( 256 , 260 ) ) ) === 'TRZF' ) { return fw . slice ( 256 ) ; } } return fw ; } ; const getChangelog = ( releases , features ) => { if ( features . bootloader_mode ) { if ( features . firmware_present && features . major_version === 1 ) { return null ; } if ( features . firmware_present && features . major_version === 2 ) { return releases . filter ( r => versionUtils . isNewer ( r . version , [ features . fw_major , features . fw_minor , features . fw_patch , ] ) ) ; } return releases ; } return releases . filter ( r => versionUtils . isNewer ( r . version , [ features . major_version , features . minor_version , features . patch_version , ] ) ) ; } ; const isNewer = ( release , features ) => { if ( features . major_version === 1 && features . bootloader_mode ) { return null ; } return versionUtils . isNewer ( release . version , [ features . major_version , features . minor_version , features . patch_version , ] ) ; } ; const isRequired = ( changelog ) => { if ( ! changelog || ! changelog . length ) return null ; return changelog . some ( item => item . required ) ; } ; const isEqual = ( release , latest ) => versionUtils . isEqual ( release . version , latest . version ) ; interface GetInfoProps { features : Features ; releases : Release [ ] ; } param features param releases export const getInfo = ( { features , releases } ) => { const parsedFeatures = parseFeatures ( features ) ; let parsedReleases = parseReleases ( releases ) ; let score = 0 ; if ( features . device_id ) { score = getScore ( features . device_id ) ; } const { bootloader_mode , major_version , minor_version , patch_version , fw_major , fw_minor , fw_patch , } = parsedFeatures ; if ( score ) { parsedReleases = parsedReleases . filter ( item => { if ( ! item . rollout ) return true ; return item . rollout >= score ; } ) ; } const latest = parsedReleases [ 0 ] ; if ( major_version === 2 && bootloader_mode ) { if ( fw_major !== null && fw_minor !== null && fw_patch !== null ) { parsedReleases = filterSafeListByFirmware ( parsedReleases , [ fw_major , fw_minor , fw_patch , ] ) ; } parsedReleases = filterSafeListByBootloader ( parsedReleases , [ major_version , minor_version , patch_version , ] ) ; } else if ( major_version === 1 && bootloader_mode ) { parsedReleases = filterSafeListByBootloader ( parsedReleases , [ major_version , minor_version , patch_version , ] ) ; } else { parsedReleases = filterSafeListByFirmware ( parsedReleases , [ major_version , minor_version , patch_version , ] ) ; } if ( ! parsedReleases . length ) { return null ; } const isLatest = isEqual ( parsedReleases [ 0 ] , latest ) ; const changelog = getChangelog ( parsedReleases , parsedFeatures ) ; return { changelog , release : parsedReleases [ 0 ] , isLatest , latest , isRequired : isRequired ( changelog ) , isNewer : isNewer ( parsedReleases [ 0 ] , parsedFeatures ) , } ; } ; interface GetBinaryProps extends GetInfoProps { baseUrl : string ; btcOnly ? : boolean ; version ? : Release [ 'version' ] ; intermediary ? : boolean ; } /**
 * Accepts version of firmware that is to be installed.
 * Also accepts features and releases list in order to validate that the provided version
 * is safe.
 * Ignores rollout (score)
 */ export const getBinary = async ( { features , releases , baseUrl , version , btcOnly , intermediary = false , } ) => { const parsedFeatures = parseFeatures ( features ) ; if ( intermediary && parsedFeatures . major_version !== 2 ) { const fw = await fetchFirmware ( `${ baseUrl }/firmware/1/trezor-inter-1.10.0.bin` ) ; return { binary : modifyFirmware ( { fw , features : parsedFeatures } ) } ; } const infoByBootloader = getInfo ( { features , releases } ) ; const releaseByFirmware = releases . find ( r => versionUtils . isEqual ( r . version , version ! ) ) ; if ( ! infoByBootloader || ! releaseByFirmware ) { throw new Error ( 'no firmware found for this device' ) ; } if ( btcOnly && ! releaseByFirmware . url_bitcoinonly ) { throw new Error ( `firmware version ${ version } does not exist in btc only variant` ) ; } if ( ! versionUtils . isEqual ( releaseByFirmware . version , infoByBootloader . release . version ) ) { throw new Error ( 'version provided as param does not match firmware version found by features in bootloader' ) ; } const fw = await fetchFirmware ( `${ baseUrl }/${ btcOnly ? releaseByFirmware . url_bitcoinonly : releaseByFirmware . url }` ) ; return { ... infoByBootloader , binary : modifyFirmware ( { fw , features : parsedFeatures } ) , } ; } ; export type FirmwareRelease = ReturnType < typeof getInfo > ; export type FirmwareBinary = ReturnType < typeof getBinary > ;