@webority/mobile-tools 0.107.0 → 0.108.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/otaNative.js +1 -1
- package/package.json +1 -1
package/lib/otaNative.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{X509Certificate}from"node:crypto";import{existsSync,readFileSync}from"node:fs";import path from"node:path";import{fail}from"./output.js";export const COMPONENT_KEY={android:"OTA_ANDROID_COMPONENT_ID",ios:"OTA_IOS_COMPONENT_ID"};const CODE_SIGNING_ALG="rsa-v1_5-sha256",KEY_ID=/^[a-z][a-z0-9]*$/,WHOLE_NUMBER=/^[1-9][0-9]*$/,isSet=e=>null!=e&&""!==e;export const componentIdFor=(e,t)=>{const i=COMPONENT_KEY[t],n=e[i];return isSet(n)?WHOLE_NUMBER.test(String(n))?String(n):fail("appConfigInvalid",`${i} must be a positive whole number, not ${JSON.stringify(n)}`):fail("appConfigInvalid",`appsettings has no ${i}: the ${t} app has no OTA component to publish to`)};export const codeSigningKeyIdOf=(e,t)=>{let i;try{i=new X509Certificate(e).subject}catch{return fail("appConfigInvalid",`${t} is not a readable X.509 certificate`)}const n=i.split("\n").filter(e=>e.startsWith("CN=")),
|
|
1
|
+
import{X509Certificate}from"node:crypto";import{existsSync,readFileSync}from"node:fs";import path from"node:path";import{fail}from"./output.js";export const COMPONENT_KEY={android:"OTA_ANDROID_COMPONENT_ID",ios:"OTA_IOS_COMPONENT_ID"};const CODE_SIGNING_ALG="rsa-v1_5-sha256",KEY_ID=/^[a-z][a-z0-9]*$/,WHOLE_NUMBER=/^[1-9][0-9]*$/,isSet=e=>null!=e&&""!==e;export const componentIdFor=(e,t)=>{const i=COMPONENT_KEY[t],n=e[i];return isSet(n)?WHOLE_NUMBER.test(String(n))?String(n):fail("appConfigInvalid",`${i} must be a positive whole number, not ${JSON.stringify(n)}`):fail("appConfigInvalid",`appsettings has no ${i}: the ${t} app has no OTA component to publish to`)};export const codeSigningKeyIdOf=(e,t)=>{let i;try{i=new X509Certificate(e).subject}catch{return fail("appConfigInvalid",`${t} is not a readable X.509 certificate`)}const n=i.split("\n").filter(e=>e.startsWith("CN=")),s=1===n.length?n[0].slice(3):"";return s.endsWith(" OTA Updates")?fail("appConfigInvalid",`${t} is the shared OTA certificate (CN=${s}), which is retired for this app: get the product's own certificate with \`bash scripts/ota-signing-key.sh cert <keyid> --out certs/ota-code-signing-cert.pem\` in the repository that owns the OTA signing keys`):KEY_ID.test(s)?s:fail("appConfigInvalid",`${t} has common name ${JSON.stringify(s)}, which is not a signing key id (a lowercase name, for example acme)`)};export const otaNativeSettings=(e,t,i,n)=>{const s=t.OTA_UPDATE_BASE_URL;if(!isSet(s)||!isSet(t[COMPONENT_KEY[n]]))return;const a=componentIdFor(t,n),o=t.OTA_PROJECT_ID;if(!isSet(o)||!WHOLE_NUMBER.test(String(o)))return fail("appConfigInvalid",`OTA_PROJECT_ID must be the update server's project id (a positive whole number), not ${JSON.stringify(o)}`);const r=t.OTA_CODE_SIGNING_CERT;if("string"!=typeof r||""===r.trim())return fail("appConfigInvalid","OTA_CODE_SIGNING_CERT must name the PEM certificate file, relative to the app folder");const p=path.join(e,r);if(!existsSync(p))return fail("appConfigInvalid",`OTA_CODE_SIGNING_CERT ${r} not found in ${e}`);const c=readFileSync(p,"utf8").replace(/\r\n/g,"\n").trim();return c.startsWith("-----BEGIN CERTIFICATE-----")?{updateUrl:`${String(s).replace(/\/+$/,"")}/ota/manifest/${o}/${a}/${i}`,runtimeVersion:String(t.VERSION_INTERNAL),certificate:c,keyId:codeSigningKeyIdOf(c,r)}:fail("appConfigInvalid",`${r} is not a PEM certificate`)};const escapeXml=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""),escapeRegExp=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),eolOf=e=>e.includes("\r\n")?"\r\n":"\n";export const androidOtaMetaData=e=>[["expo.modules.updates.ENABLED","true"],["expo.modules.updates.EXPO_UPDATE_URL",e.updateUrl],["expo.modules.updates.EXPO_RUNTIME_VERSION",e.runtimeVersion],["expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH","ALWAYS"],["expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS","0"],["expo.modules.updates.CODE_SIGNING_CERTIFICATE",e.certificate],["expo.modules.updates.CODE_SIGNING_METADATA",JSON.stringify({keyid:e.keyId,alg:CODE_SIGNING_ALG})]];const childIndent=(e,t)=>{const i=e.split(/\r?\n/).filter(e=>""!==e.trim()),n=/^[ \t]*/.exec(i[i.length-1]??"")?.[0]??"";return n.length>t.length?n:`${t} `};export const rewriteAndroidManifestOta=(e,t)=>{const i=eolOf(e);let n=e;const s=[];for(const[e,i]of androidOtaMetaData(t)){const t=escapeXml(i).replace(/\n/g," "),a=new RegExp(`(<meta-data\\s+android:name="${escapeRegExp(e)}"\\s+android:value=")[^"]*(")`);a.test(n)?n=n.replace(a,(e,i,n)=>`${i}${t}${n}`):s.push([e,t])}if(0===s.length)return n;const a=/^([ \t]*)<\/application>/m.exec(n);if(!a)return fail("appConfigInvalid","AndroidManifest.xml has no </application> to add the expo-updates settings to");const o=childIndent(n.slice(0,a.index),a[1]),r=s.map(([e,t])=>`${o}<meta-data android:name="${e}" android:value="${t}" />`).join(i);return`${n.slice(0,a.index)}${r}${i}${n.slice(a.index)}`};export const iosOtaPlistKeys=e=>[["EXUpdatesEnabled",!0],["EXUpdatesURL",e.updateUrl],["EXUpdatesRuntimeVersion",e.runtimeVersion],["EXUpdatesCheckOnLaunch","ALWAYS"],["EXUpdatesLaunchWaitMs",0],["EXUpdatesCodeSigningCertificate",e.certificate],["EXUpdatesCodeSigningMetadata",{keyid:e.keyId,alg:CODE_SIGNING_ALG}]];const plistValue=(e,t,i)=>{if("boolean"==typeof e)return e?"<true/>":"<false/>";if("number"==typeof e)return`<integer>${e}</integer>`;if("string"==typeof e)return`<string>${escapeXml(e).replace(/\n/g,i)}</string>`;const n=`${t}${t.includes("\t")?"\t":" "}`,s=Object.entries(e).map(([e,t])=>`${n}<key>${escapeXml(e)}</key>${i}${n}<string>${escapeXml(t)}</string>`).join(i);return`<dict>${i}${s}${i}${t}</dict>`},PLIST_VALUE=String.raw`(?:<(?:true|false)\/>|<string>[\s\S]*?<\/string>|<integer>[^<]*<\/integer>|<dict>[\s\S]*?<\/dict>|<dict\/>)`;export const rewriteExpoPlistOta=(e,t)=>{const i=eolOf(e);let n=e;const s=[];for(const[e,a]of iosOtaPlistKeys(t)){const t=new RegExp(`([ \\t]*)(<key>${escapeRegExp(e)}<\\/key>\\s*)${PLIST_VALUE}`).exec(n);if(t){const e=t[1];n=`${n.slice(0,t.index)}${e}${t[2]}${plistValue(a,e,i)}${n.slice(t.index+t[0].length)}`}else s.push([e,a])}if(0===s.length)return n;const a=/^([ \t]*)<\/dict>\s*<\/plist>/m.exec(n);if(!a)return fail("appConfigInvalid","Expo.plist has no root </dict> to add the expo-updates settings to");const o=childIndent(n.slice(0,a.index),a[1]),r=s.map(([e,t])=>`${o}<key>${escapeXml(e)}</key>${i}${o}${plistValue(t,o,i)}`).join(i);return`${n.slice(0,a.index)}${r}${i}${n.slice(a.index)}`};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/mobile-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.108.1",
|
|
4
4
|
"description": "Dev-time CLI for Webority React Native apps: one prebuild, a dependency guard, a device-aware run and per-environment launcher icons, the same on Windows and macOS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|