-
Notifications
You must be signed in to change notification settings - Fork 11
/
index.js
124 lines (110 loc) · 5.13 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
const core = require('@actions/core');
const shell = require('shelljs');
const jwt = require('jsonwebtoken');
const axios = require('axios');
const path = require('path');
const os = require('os');
function getToken(issuerID, minute, privateKey, keyId) {
const payload = {
exp: Math.floor(Date.now() / 1000) + (minute * 60),
aud: "appstoreconnect-v1",
iss: issuerID
};
const options = {
algorithm: "ES256",
header: {
kid: keyId
}
}
return jwt.sign(payload, privateKey, options);
}
async function get(url, params, token, method = "GET") {
const options = {
url: url,
method: method,
headers: {
'Authorization': `Bearer ${token}`
},
params: params
}
const response = await axios.request(options);
return response.data;
}
/**
* Resolves paths that start with a ~ to the user's home directory.
*
* @param {string} filePath '~/GitHub/Repo/file.png'
* @return {string} '/home/bob/GitHub/Repo/file.png'
*/
function resolveTilde(filePath) {
if (!filePath || typeof(filePath) !== 'string') {
return '';
}
// '~/folder/path' or '~' not '~alias/folder/path'
if (filePath.startsWith('~/') || filePath === '~') {
return filePath.replace('~', os.homedir());
}
return filePath;
}
function provisioningProfilePath(profileUUID) {
const profileName = `${profileUUID}.mobileprovision`;
// Resolve ~ as the node.js shell.exec command does not resolve ~ correctly
return resolveTilde(`~/Library/MobileDevice/Provisioning Profiles/${profileName}`);
}
function setupProvisioning(profileContentBase64, provisioningProfilePath) {
const provisioningProfileDir = path.dirname(provisioningProfilePath)
shell.exec(`mkdir -p "${provisioningProfileDir}"`);
shell.exec(`(echo ${profileContentBase64} | base64 --decode) > "${provisioningProfilePath}"`);
}
function setupKeychain(keychainName, keychainPassword, base64P12File, p12Password) {
const tempCertificateName = `tmp.p12`;
shell.exec(`(echo "${base64P12File}" | base64 --decode) > "${tempCertificateName}"`);
shell.exec(`security create-keychain -p "${keychainPassword}" "${keychainName}"`);
shell.exec(`security list-keychains -d user -s login.keychain "${keychainName}"`);
shell.exec(`security import "${tempCertificateName}" -A -k "${keychainName}" -P "${p12Password}"`);
shell.exec(`security set-keychain-settings -lut 1000 "${keychainName}"`);
shell.exec(`security default-keychain -s "${keychainName}"`);
shell.exec(`security unlock-keychain -p "${keychainPassword}" "${keychainName}"`);
shell.exec(`security set-key-partition-list -S apple-tool:,apple: -s -k "${keychainPassword}" "${keychainName}"`);
shell.exec(`rm ${tempCertificateName}`);
}
async function run() {
try {
const appStoreConnectPrivateKey = core.getInput(`appStoreConnectPrivateKey`);
const keyID = core.getInput(`keyID`);
const issuerID = core.getInput(`issuerID`);
const keychainName = core.getInput(`keychainName`);
const keychainPassword = core.getInput(`keychainPassword`);
const base64P12File = core.getInput(`base64P12File`);
const p12Password = core.getInput(`p12Password`);
const bundleIdentifier = core.getInput(`bundleIdentifier`);
const signType = core.getInput(`signType`);
const token = getToken(issuerID, 2, Buffer.from(appStoreConnectPrivateKey, "utf8"), keyID);
const bundleIdResponse = await get("https://api.appstoreconnect.apple.com/v1/bundleIds", { "filter[identifier]": bundleIdentifier }, token); // BundleIdsResponse Type
const bundleId = bundleIdResponse.data.find(element => element.attributes.identifier == bundleIdentifier);
if (bundleId) {
const profileIds = await get(`https://api.appstoreconnect.apple.com/v1/bundleIds/${bundleId.id}/relationships/profiles`, { }, token);
const rawProfileIds = profileIds.data.map(profile => profile.id);
if (rawProfileIds) {
const profilesResponse = await get("https://api.appstoreconnect.apple.com/v1/profiles", { "filter[id]": `${rawProfileIds}`, "filter[profileType]": signType }, token); // ProfilesResponse Type
const profile = profilesResponse.data[0];
if (profile) {
const profileContent = profile.attributes.profileContent;
const profileUUID = profile.attributes.uuid;
const pathToProvisioningProfile = provisioningProfilePath(profileUUID)
setupProvisioning(profileContent, pathToProvisioningProfile);
setupKeychain(keychainName, keychainPassword, base64P12File, p12Password);
} else {
throw new Error(`Could not find matching provisioning profile for ${bundleIdentifier} on Developer Portal. Please check it on https://developer.apple.com/account/`);
}
} else {
throw new Error(`Could not find provisioning profiles for ${bundleIdentifier} on Developer Portal. Please check it on https://developer.apple.com/account/resources/profiles/list`);
}
} else {
throw new Error(`Could not find bundleIdentifier ${bundleIdentifier} on Developer Portal. Please check it on https://developer.apple.com/account/resources/identifiers/list`);
}
} catch (error) {
core.setFailed(error.message);
}
}
run();