mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
Website: Add first version of android settings to configuration builder. (#31939)
Changes: - Updated the configuration builder to support creating Android policies. - Added two categories of Android settings to the configuration builder.
This commit is contained in:
parent
58233817f0
commit
03e1bb1d3b
4 changed files with 601 additions and 115 deletions
BIN
website/assets/images/icon-android-24x24@2x.png
vendored
Normal file
BIN
website/assets/images/icon-android-24x24@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 407 B |
|
|
@ -65,7 +65,7 @@ parasails.registerPage('configuration-builder', {
|
|||
downloadProfileFormData: {},
|
||||
profileFilename: undefined,
|
||||
profileDescription: undefined,
|
||||
// mac OS payloads.
|
||||
// macOS payloads.
|
||||
macosCategoriesAndPayloads: [
|
||||
{
|
||||
categoryName: 'Privacy & security',
|
||||
|
|
@ -92,31 +92,10 @@ parasails.registerPage('configuration-builder', {
|
|||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingKey: 'forcePIN',
|
||||
trueValue: '<true/>',
|
||||
falseValue: '<false/>',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Allow simple password',
|
||||
uniqueSlug: 'macos-enable-allow-simple-pin',
|
||||
tooltip: 'If false, the system prevents use of a simple passcode. A simple passcode contains repeated characters, or increasing or decreasing characters, such as 123 or CBA.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'boolean',
|
||||
trueValue: 0,
|
||||
falseValue: 1
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingKey: 'allowSimple',
|
||||
trueValue: '<true/>',
|
||||
falseValue: '<false/>',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Max inactivity time before device locks',
|
||||
name: 'Maximum inactivity time before device locks',
|
||||
uniqueSlug: 'macos-max-inactivity',
|
||||
tooltip: 'The maximum number of minutes for which the device can be idle without the user unlocking it, before the system locks it.',
|
||||
category: 'Device lock',
|
||||
|
|
@ -153,6 +132,23 @@ parasails.registerPage('configuration-builder', {
|
|||
settingKey: 'minLength',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Allow simple password',
|
||||
uniqueSlug: 'macos-enable-allow-simple-pin',
|
||||
tooltip: 'If false, the system prevents use of a simple passcode. A simple passcode contains repeated characters, or increasing or decreasing characters, such as 123 or CBA.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'boolean',
|
||||
trueValue: 0,
|
||||
falseValue: 1
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingKey: 'allowSimple',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Require alphanumeric password',
|
||||
uniqueSlug: 'macos-require-alphanumeric-password',
|
||||
|
|
@ -170,80 +166,6 @@ parasails.registerPage('configuration-builder', {
|
|||
settingKey: 'requireAlphanumeric',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Change passcode at next login',
|
||||
uniqueSlug: 'macos-change-at-next-auth',
|
||||
tooltip: 'If true, the system causes a password reset to occur the next time the user tries to authenticate.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'boolean',
|
||||
trueValue: 0,
|
||||
falseValue: 1
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingKey: 'changeAtNextAuth',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Maximum number of failed attempts',
|
||||
uniqueSlug: 'macos-max-failed-attempts',
|
||||
tooltip: 'The number of allowed failed attempts to enter the passcode at the device’s lock screen. After four failed attempts, the system imposes a time delay before a passcode can be entered again. When this number is exceeded in macOS, the system locks the device.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
defaultValue: 11,
|
||||
minValue: 2,
|
||||
maxValue: 11,
|
||||
unitLabel: 'attempts'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'maxFailedAttempts',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Max grace period',
|
||||
uniqueSlug: 'macos-max-grace-period',
|
||||
tooltip: 'The maximum grace period, in minutes, to unlock the device without entering a passcode. The default is 0, which is no grace period and requires a passcode immediately.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
defaultValue: 0,
|
||||
minValue: 0,
|
||||
maxValue: 999,
|
||||
unitLabel: 'minutes'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'maxGracePeriod',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Max passcode age',
|
||||
uniqueSlug: 'macos-max-pin-age',
|
||||
tooltip: 'The number of days for which the passcode can remain unchanged. After this number of days, the system forces the user to change the passcode before it unlocks the device.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
defaultValue: 0,
|
||||
minValue: 0,
|
||||
maxValue: 999,
|
||||
unitLabel: 'days'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'maxPINAgeInDays',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum complex characters',
|
||||
uniqueSlug: 'macos-min-complex-characters',
|
||||
|
|
@ -264,9 +186,26 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: 'Minutes until failed login reset',
|
||||
uniqueSlug: 'macos-minutes-until-failed-login-reset',
|
||||
tooltip: 'The number of minutes before the system resets the login after the maximum number of unsuccessful login attempts is reached.',
|
||||
name: 'Change passcode at next login',
|
||||
uniqueSlug: 'macos-change-at-next-auth',
|
||||
tooltip: 'If true, the system causes a password reset to occur the next time the user tries to authenticate.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'boolean',
|
||||
trueValue: 0,
|
||||
falseValue: 1
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingKey: 'changeAtNextAuth',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Maximum grace period',
|
||||
uniqueSlug: 'macos-max-grace-period',
|
||||
tooltip: 'The maximum grace period, in minutes, to unlock the device without entering a passcode. The default is 0, which is no grace period and requires a passcode immediately.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
|
|
@ -274,12 +213,12 @@ parasails.registerPage('configuration-builder', {
|
|||
type: 'number',
|
||||
defaultValue: 0,
|
||||
minValue: 0,
|
||||
maxValue: 4,
|
||||
maxValue: 999,
|
||||
unitLabel: 'minutes'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'minutesUntilFailedLoginReset',
|
||||
settingKey: 'maxGracePeriod',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -299,6 +238,63 @@ parasails.registerPage('configuration-builder', {
|
|||
settingKey: 'pinHistory',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Maximum passcode age',
|
||||
uniqueSlug: 'macos-max-pin-age',
|
||||
tooltip: 'The number of days for which the passcode can remain unchanged. After this number of days, the system forces the user to change the passcode before it unlocks the device.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
defaultValue: 0,
|
||||
minValue: 0,
|
||||
maxValue: 999,
|
||||
unitLabel: 'days'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'maxPINAgeInDays',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Maximum number of failed attempts',
|
||||
uniqueSlug: 'macos-max-failed-attempts',
|
||||
tooltip: 'The number of allowed failed attempts to enter the passcode at the device’s lock screen. After four failed attempts, the system imposes a time delay before a passcode can be entered again. When this number is exceeded in macOS, the system locks the device.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
defaultValue: 11,
|
||||
minValue: 2,
|
||||
maxValue: 11,
|
||||
unitLabel: 'attempts'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'maxFailedAttempts',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minutes until failed login reset',
|
||||
uniqueSlug: 'macos-minutes-until-failed-login-reset',
|
||||
tooltip: 'The number of minutes before the system resets the login after the maximum number of unsuccessful login attempts is reached.',
|
||||
category: 'Device lock',
|
||||
payload: 'Passcode',
|
||||
payloadType: 'com.apple.mobiledevice.passwordpolicy',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
defaultValue: 0,
|
||||
minValue: 0,
|
||||
maxValue: 4,
|
||||
unitLabel: 'minutes'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'integer',
|
||||
settingKey: 'minutesUntilFailedLoginReset',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
|
|
@ -1079,7 +1075,7 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: 'Max inactivity time before device locks',
|
||||
name: 'Maximum inactivity time before device locks',
|
||||
uniqueSlug: 'windows-device-lock-max-inactivity-before-device-locks',
|
||||
category: 'Device lock',
|
||||
tooltip: 'The number of seconds a device can remain inactive before a password is required to unlock the device.',
|
||||
|
|
@ -1102,7 +1098,7 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: 'Max inactivity time before device locks with external display',
|
||||
name: 'Maximum inactivity time before device locks with external display',
|
||||
uniqueSlug: 'windows-device-lock-max-inactivity-before-device-locks-with-external-display',
|
||||
category: 'Device lock',
|
||||
tooltip: 'The number of seconds a device can remain inactive while using an external monitor before a password is required to unlock the device.',
|
||||
|
|
@ -1158,7 +1154,7 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: 'Max failed attempts',
|
||||
name: 'Maximum failed attempts',
|
||||
tooltip: 'The number of authentication failures allowed before the device will be wiped. A value of 0 disables device wipe functionality.',
|
||||
uniqueSlug: 'windows-device-lock-max-failed-attempts',
|
||||
category: 'Device lock',
|
||||
|
|
@ -1182,7 +1178,7 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: 'Max password age',
|
||||
name: 'Maximum password age',
|
||||
tooltip: `Determines the period of time (in days) that a password can be used before the system requires the user to change it. You can set passwords to expire after a number of days between 1 and 999, or you can specify that passwords never expire by setting the number of days to 0.`,
|
||||
uniqueSlug: 'windows-device-lock-max-password-age',
|
||||
category: 'Device lock',
|
||||
|
|
@ -2681,6 +2677,443 @@ parasails.registerPage('configuration-builder', {
|
|||
],
|
||||
}
|
||||
],
|
||||
// Android payloads
|
||||
androidCategoriesAndPayloads: [
|
||||
{
|
||||
categoryName: 'Privacy & security',
|
||||
categorySlug: 'android-privacy-and-security',
|
||||
subcategories: [
|
||||
{
|
||||
subcategoryName: 'Device lock',
|
||||
subcategorySlug: 'android-device-lock',
|
||||
description: 'Settings related to screen lock and passwords.',
|
||||
learnMoreLinkUrl: 'https://developers.google.com/android/management/reference/rest/v1/enterprises.policies',
|
||||
payloads: [
|
||||
{
|
||||
name: 'Maximum inactivity time before device locks',
|
||||
uniqueSlug: 'android-max-inactivity',
|
||||
tooltip: 'Maximum time in milliseconds for user activity until the device locks. A value of 0 means there is no restriction.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Screen lock',// determines the
|
||||
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'milliseconds'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'maximumTimeToLock',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Password history length',
|
||||
uniqueSlug: 'android-password-history',
|
||||
tooltip: `The length of the password history. After setting this field, the user won't be able to enter a new password that is the same as any password in the history. A value of 0 means there is no restriction.`,
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'passwords'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordHistoryLength',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Maximum number of failed attempts before device is wiped.',
|
||||
uniqueSlug: 'android-password-max-failed-attempts',
|
||||
tooltip: `Number of incorrect device-unlock passwords that can be entered before a device is wiped. A value of 0 means there is no restriction.`,
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'attempts'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.maximumFailedPasswordsForWipe',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Password scope',
|
||||
uniqueSlug: 'android-password-scope',
|
||||
tooltip: `The scope that the password requirement applies to.`,
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
name: 'Unspecified',
|
||||
value: 'SCOPE_UNSPECIFIED'
|
||||
},
|
||||
{
|
||||
name: 'Device',
|
||||
value: 'SCOPE_DEVICE'
|
||||
},
|
||||
{
|
||||
name: 'Work profile',
|
||||
value: 'SCOPE_PROFILE',
|
||||
},
|
||||
]
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'passwordRequirements.passwordScope',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Amount of time after unlocking before a password is required again',
|
||||
uniqueSlug: 'android-require-password-unlock-timeout',
|
||||
tooltip: `The length of time after a device or work profile is unlocked using a strong form of authentication (password, PIN, pattern) that it can be unlocked using any other authentication method (e.g. fingerprint, trust agents, face). After the specified time period elapses, only strong forms of authentication can be used to unlock the device or work profile.`,
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
name: 'Unspecified',
|
||||
value: 'REQUIRE_PASSWORD_UNLOCK_UNSPECIFIED'
|
||||
},
|
||||
{
|
||||
name: `Device's default`,
|
||||
value: 'USE_DEFAULT_DEVICE_TIMEOUT'
|
||||
},
|
||||
{
|
||||
name: 'Every 24 hours',
|
||||
value: 'REQUIRE_EVERY_DAY',
|
||||
},
|
||||
]
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'passwordRequirements.requirePasswordUnlock',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Enforce password complexity',
|
||||
uniqueSlug: 'android-password-complexity',
|
||||
tooltip: 'Password quality requirements.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
name: 'The device must be secured with a low-security biometric recognition technology, at minimum. This includes technologies that can recognize the identity of an individual that are roughly equivalent to a 3-digit PIN',
|
||||
value: 'BIOMETRIC_WEAK'
|
||||
},
|
||||
{
|
||||
name: 'A password is required, but there are no restrictions on what the password must contain.',
|
||||
value: 'SOMETHING'
|
||||
},
|
||||
{
|
||||
name: 'Numeric - The password must contain numeric characters.',
|
||||
value: 'NUMERIC',
|
||||
},
|
||||
{
|
||||
name: 'Complex numeric - The password must contain numeric characters with no repeating (4444) or ordered (1234, 4321, 2468) sequences.',
|
||||
value: 'NUMERIC_COMPLEX',
|
||||
},
|
||||
{
|
||||
name: 'Alphabetic - The password must contain alphabetic (or symbol) characters.',
|
||||
value: 'ALPHABETIC',
|
||||
},
|
||||
{
|
||||
name: 'Alphanumeric - The password must contain both numeric and alphabetic (or symbol) characters.',
|
||||
value: 'ALPHANUMERIC',
|
||||
},
|
||||
{
|
||||
name: 'Complex - The password must meet the requirments set by this policy',
|
||||
value: 'COMPLEX',
|
||||
},
|
||||
]
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'passwordRequirements.passwordQuality',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum password length',
|
||||
uniqueSlug: 'android-min-password-length',
|
||||
tooltip: 'The minimum allowed password length. A value of 0 means there is no restriction. Only enforced when password complexity is set to numeric, complex numeric, alphabetic, alphanumeric, or complex.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'characters'
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumLength',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum number of letters in password',
|
||||
uniqueSlug: 'android-min-password-letters',
|
||||
tooltip: 'Minimum number of letters required in the password. Only enforced when password complexity is set to complex.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'letters'
|
||||
},
|
||||
alsoAutoSetWhenSelected: [
|
||||
{
|
||||
dependingOnSettingSlug: 'android-password-complexity',
|
||||
dependingOnSettingValue: 'COMPLEX',
|
||||
}
|
||||
],
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumLetters',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum number of lower case letters in password',
|
||||
uniqueSlug: 'android-min-password-letters-lower-case',
|
||||
tooltip: 'Minimum number of lower case letters required in the password. Only enforced when password complexity is set to complex.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'lower case letters'
|
||||
},
|
||||
alsoAutoSetWhenSelected: [
|
||||
{
|
||||
dependingOnSettingSlug: 'android-password-complexity',
|
||||
dependingOnSettingValue: 'COMPLEX',
|
||||
}
|
||||
],
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumLowerCase',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum number of upper case letters in password',
|
||||
uniqueSlug: 'android-min-password-letters-upper-case',
|
||||
tooltip: 'Minimum number of upper case letters required in the password. Only enforced when password complexity is set to complex.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'lower case letters'
|
||||
},
|
||||
alsoAutoSetWhenSelected: [
|
||||
{
|
||||
dependingOnSettingSlug: 'android-password-complexity',
|
||||
dependingOnSettingValue: 'COMPLEX',
|
||||
}
|
||||
],
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumUpperCase',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum number of non-letter characters in password',
|
||||
uniqueSlug: 'android-min-password-non-letters',
|
||||
tooltip: 'Minimum number of non-letter characters (numerical digits or symbols) required in the password. Only enforced when password complexity is set to complex.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'characters'
|
||||
},
|
||||
alsoAutoSetWhenSelected: [
|
||||
{
|
||||
dependingOnSettingSlug: 'android-password-complexity',
|
||||
dependingOnSettingValue: 'COMPLEX',
|
||||
}
|
||||
],
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumNonLetter',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum number of numerical digits in password',
|
||||
uniqueSlug: 'android-min-password-numeric',
|
||||
tooltip: 'Minimum number of numerical digits required in the password. Only enforced when password complexity is set is COMPLEX.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'digits'
|
||||
},
|
||||
alsoAutoSetWhenSelected: [
|
||||
{
|
||||
dependingOnSettingSlug: 'android-password-complexity',
|
||||
dependingOnSettingValue: 'COMPLEX',
|
||||
}
|
||||
],
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumNumeric',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Minimum number of symbols in password',
|
||||
uniqueSlug: 'android-min-password-symbols',
|
||||
tooltip: 'Minimum number of symbols required in the password. Only enforced when password complexity is set is COMPLEX.',
|
||||
category: 'Device lock',
|
||||
payloadGroup: 'Password',
|
||||
formInput: {
|
||||
type: 'number',
|
||||
unitLabel: 'symbols'
|
||||
},
|
||||
alsoAutoSetWhenSelected: [
|
||||
{
|
||||
dependingOnSettingSlug: 'android-password-complexity',
|
||||
dependingOnSettingValue: 'COMPLEX',
|
||||
}
|
||||
],
|
||||
formOutput: {
|
||||
settingFormat: 'number',
|
||||
settingTargetPath: 'passwordRequirements.passwordMinimumSymbols',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
categoryName: 'Software & updates',
|
||||
categorySlug: 'android-software-and-updates',
|
||||
subcategories: [
|
||||
{
|
||||
subcategoryName: 'Applications',
|
||||
subcategorySlug: 'android-applications',
|
||||
description: 'Settings related to Applications and the Google play store on Android devices.',
|
||||
learnMoreLinkUrl: 'https://developers.google.com/android/management/reference/rest/v1/enterprises.policies',
|
||||
payloads: [
|
||||
{
|
||||
name: 'Apply device-wide app update policy',
|
||||
uniqueSlug: 'android-app-auto-update-policy',
|
||||
tooltip: `The app auto-update policy, which controls when automatic app updates can be applied.`,
|
||||
category: 'Applications',
|
||||
formInput: {
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
name: 'Unspecified',
|
||||
value: 'APP_AUTO_UPDATE_POLICY_UNSPECIFIED'
|
||||
},
|
||||
{
|
||||
name: 'The user can control auto-updates.',
|
||||
value: 'CHOICE_TO_THE_USER'
|
||||
},
|
||||
{
|
||||
name: 'Apps are never auto-updated',
|
||||
value: 'NEVER',
|
||||
},
|
||||
{
|
||||
name: 'Apps are auto-updated over Wi-Fi only.',
|
||||
value: 'WIFI_ONLY',
|
||||
},
|
||||
{
|
||||
name: 'Apps are auto-updated at any time.',
|
||||
value: 'ALWAYS',
|
||||
},
|
||||
]
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'appAutoUpdatePolicy',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Disable app installation',
|
||||
uniqueSlug: 'android-disable-app-install',
|
||||
tooltip: `Whether user installation of apps is disabled.`,
|
||||
category: 'Applications',
|
||||
formInput: {
|
||||
type: 'boolean',
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingTargetPath: 'installAppsDisabled',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Disable app uninstallation',
|
||||
uniqueSlug: 'android-disable-app-uninstall',
|
||||
tooltip: `Whether user uninstallation of applications is disabled.`,
|
||||
category: 'Applications',
|
||||
formInput: {
|
||||
type: 'boolean',
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'boolean',
|
||||
settingTargetPath: 'uninstallAppsDisabled',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Allow installation of untrusted applications',
|
||||
uniqueSlug: 'android-untrusted-apps',
|
||||
tooltip: `The app auto-update policy, which controls when automatic app updates can be applied.`,
|
||||
category: 'Applications',
|
||||
formInput: {
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
name: 'Unspecified',
|
||||
value: 'UNTRUSTED_APPS_POLICY_UNSPECIFIED'
|
||||
},
|
||||
{
|
||||
name: 'Disallow untrusted app installs on entire device.',
|
||||
value: 'DISALLOW_INSTALL'
|
||||
},
|
||||
{
|
||||
name: 'For devices with work profiles, allow untrusted app installs in the device\'s personal profile only.',
|
||||
value: 'ALLOW_INSTALL_IN_PERSONAL_PROFILE_ONLY',
|
||||
},
|
||||
{
|
||||
name: 'Allow untrusted app installs on entire device.',
|
||||
value: 'ALLOW_INSTALL_DEVICE_WIDE',
|
||||
},
|
||||
]
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'advancedSecurityOverrides.untrustedAppsPolicy',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Enforce Google Play protect verification',
|
||||
uniqueSlug: 'android-google-play-protect',
|
||||
tooltip: `The app auto-update policy, which controls when automatic app updates can be applied.`,
|
||||
category: 'Applications',
|
||||
formInput: {
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
name: 'Unspecified',
|
||||
value: 'GOOGLE_PLAY_PROTECT_VERIFY_APPS_UNSPECIFIED'
|
||||
},
|
||||
{
|
||||
name: 'Enforce app verification.',
|
||||
value: 'VERIFY_APPS_ENFORCED'
|
||||
},
|
||||
{
|
||||
name: 'Allows the user to choose whether to enable app verification.',
|
||||
value: 'VERIFY_APPS_USER_CHOICE',
|
||||
},
|
||||
]
|
||||
},
|
||||
formOutput: {
|
||||
settingFormat: 'string',
|
||||
settingTargetPath: 'advancedSecurityOverrides.googlePlayProtectVerifyApps',
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
|
|
@ -2727,6 +3160,8 @@ parasails.registerPage('configuration-builder', {
|
|||
await this.buildWindowsProfile(this.selectedPayloads);
|
||||
} else if(this.selectedPlatform === 'macos') {
|
||||
await this.buildMacOSProfile(this.selectedPayloads);
|
||||
} else if(this.selectedPlatform === 'android') {
|
||||
await this.buildAndroidProfile(this.selectedPayloads);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2740,6 +3175,28 @@ parasails.registerPage('configuration-builder', {
|
|||
await this.buildMacOSProfile(this.selectedPayloads);
|
||||
}
|
||||
},
|
||||
buildAndroidProfile: function(selectedPayloads) {
|
||||
let thisProfile = {
|
||||
name: this.downloadProfileFormData.name,
|
||||
version: this.downloadProfileFormData.version,
|
||||
};
|
||||
let payloadsToUse = _.clone(selectedPayloads);
|
||||
for(let payload of payloadsToUse ){
|
||||
if(payload.formOutput.settingFormat === 'number'){
|
||||
let formDataCastToANumber = Number(this.configurationBuilderFormData[payload.uniqueSlug+'-value']);
|
||||
_.set(thisProfile, payload.formOutput.settingTargetPath, formDataCastToANumber);
|
||||
} else {
|
||||
_.set(thisProfile, payload.formOutput.settingTargetPath, this.configurationBuilderFormData[payload.uniqueSlug+'-value']);
|
||||
}
|
||||
}
|
||||
let profileDownloadUrl = URL.createObjectURL(new Blob([JSON.stringify(thisProfile)], { type: 'text/json;' }));
|
||||
let exportDownloadLink = document.createElement('a');
|
||||
exportDownloadLink.href = profileDownloadUrl;
|
||||
exportDownloadLink.download = `${this.downloadProfileFormData.name}.json`;
|
||||
exportDownloadLink.click();
|
||||
URL.revokeObjectURL(profileDownloadUrl);
|
||||
this.syncing = false;
|
||||
},
|
||||
buildWindowsProfile: function(payloadsToUse) {
|
||||
let xmlString = '';
|
||||
// Iterate through the selcted payloads
|
||||
|
|
@ -2936,7 +3393,7 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
// When users click the download all button.
|
||||
handleSubmittingConfigurationBuilderForm: function() {
|
||||
if(_.keysIn(this.selectedPayloadsGroupedByCategory).length > 1) {
|
||||
if(_.keysIn(this.selectedPayloadsGroupedByCategory).length > 1 && this.selectedPlatform !== 'android') {
|
||||
// If there is more than one payload in this profile, show a warning in a modal.
|
||||
this.modal = 'multiple-payloads-selected';
|
||||
} else {
|
||||
|
|
@ -2953,7 +3410,7 @@ parasails.registerPage('configuration-builder', {
|
|||
},
|
||||
openDownloadModal: function() {
|
||||
this.modal = 'download-profile';
|
||||
if(this.selectedPlatform === 'macos'){
|
||||
if(this.selectedPlatform === 'macos') {
|
||||
this.downloadProfileFormRules = {
|
||||
name: {required: true},
|
||||
uuid: {required: true},
|
||||
|
|
@ -2961,6 +3418,11 @@ parasails.registerPage('configuration-builder', {
|
|||
};
|
||||
// Generate a uuid to prefill for the download profile form.
|
||||
this.downloadProfileFormData.uuid = crypto.randomUUID();
|
||||
} else if(this.selectedPlatform === 'android') {
|
||||
this.downloadProfileFormRules = {
|
||||
name: {required: true},
|
||||
version: { required: true }
|
||||
};
|
||||
}
|
||||
this._enableToolTips();
|
||||
},
|
||||
|
|
@ -3060,7 +3522,7 @@ parasails.registerPage('configuration-builder', {
|
|||
}
|
||||
this.selectedPayloadsGroupedByCategory = _.groupBy(this.selectedPayloads, 'category');
|
||||
this.selectedPayloadSettings[payloadSlug] = true;
|
||||
// console.log(this.configurationBuilderFormData);
|
||||
|
||||
} else {
|
||||
// Remove the payload option and all dependencies
|
||||
let payloadToRemove = _.find(this.selectedPayloads, {uniqueSlug: payloadSlug});
|
||||
|
|
|
|||
|
|
@ -97,8 +97,6 @@
|
|||
}
|
||||
}
|
||||
[purpose='platform-selector'] {
|
||||
// height: 372px;
|
||||
max-width: 435px;
|
||||
padding: 48px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -108,13 +106,20 @@
|
|||
box-shadow: 0px 0px 0px 2px rgba(25, 33, 71, 0.05);
|
||||
align-items: flex-start;
|
||||
position: absolute;
|
||||
right: calc(~'50% - 216.5px');
|
||||
right: calc(~'50% - 324px');
|
||||
top: calc(~'50% - 186px');
|
||||
h2 {
|
||||
color: #192147;
|
||||
font-family: Inter;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 24px; /* 120% */
|
||||
}
|
||||
}
|
||||
|
||||
[purpose='platform-button'] {
|
||||
display: flex;
|
||||
height: 120px;
|
||||
height: 100px;
|
||||
padding: 16px 64px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
|
@ -129,6 +134,8 @@
|
|||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
text-select: none;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
img {
|
||||
height: 24px;
|
||||
margin-bottom: 8px;
|
||||
|
|
|
|||
21
website/views/pages/configuration-builder.ejs
vendored
21
website/views/pages/configuration-builder.ejs
vendored
|
|
@ -43,14 +43,18 @@
|
|||
<p class="mb-0">Choose an operating system to continue.</p>
|
||||
<ajax-form :handle-submitting="handleSubmittingPlatformSelectForm" :form-errors.sync="formErrors" :form-data="platformSelectFormData" :form-rules="platformSelectFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
|
||||
<div purpose="platforms" id="platform" class="d-flex flex-row">
|
||||
<div purpose="platform-button" :class="[formErrors.platform ? 'is-invalid' : platformSelectFormData.platform === 'macos' ? 'selected' : '' ]" style="margin-right: 10px;" @click="platformSelectFormData.platform = 'macos'">
|
||||
<div purpose="platform-button" class="mb-3" :class="[formErrors.platform ? 'is-invalid' : platformSelectFormData.platform === 'macos' ? 'selected' : '' ]" @click="platformSelectFormData.platform = 'macos'">
|
||||
<img src="/images/os-macos-dark-24x24@2x.png" alt="macOS" class="d-inline">
|
||||
macOS
|
||||
</div>
|
||||
<div purpose="platform-button" :class="[formErrors.platform ? 'is-invalid' : platformSelectFormData.platform === 'windows' ? 'selected' : '' ]" @click="platformSelectFormData.platform = 'windows'">
|
||||
<div purpose="platform-button" class="mb-0" :class="[formErrors.platform ? 'is-invalid' : platformSelectFormData.platform === 'windows' ? 'selected' : '' ]" @click="platformSelectFormData.platform = 'windows'">
|
||||
<img src="/images/os-windows-dark-24x24@2x.png" alt="Windows" class="d-inline">
|
||||
Windows
|
||||
</div>
|
||||
<div purpose="platform-button" :class="[formErrors.platform ? 'is-invalid' : platformSelectFormData.platform === 'android' ? 'selected' : '' ]" @click="platformSelectFormData.platform = 'android'">
|
||||
<img src="/images/icon-android-24x24@2x.png" alt="Android" class="d-inline">
|
||||
Android
|
||||
</div>
|
||||
</div>
|
||||
<div class="invalid-feedback" v-if="formErrors.platform">Please select an option</div>
|
||||
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary" :syncing="syncing" v-if="platformSelectFormData.platform">Create</ajax-button>
|
||||
|
|
@ -88,6 +92,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div purpose="category-options" v-if="selectedPlatform === 'android'">
|
||||
<div v-for="category in androidCategoriesAndPayloads">
|
||||
<a @click="clickExpandCategory(category.categorySlug)" :class="[expandedCategory === category.categorySlug ? 'selected' : '' ]" >{{category.categoryName}}</a>
|
||||
<div purpose="subcategories" v-if="expandedCategory === category.categorySlug">
|
||||
<a @click="clickSelectPayloadCategory(subcategory)" v-for="subcategory in category.subcategories">{{subcategory.subcategoryName}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%
|
||||
|
|
@ -355,6 +367,11 @@
|
|||
<input type="text" :class="[formErrors.uuid ? 'is-invalid' : '']" class="form-control" id="uuid" v-model="downloadProfileFormData.uuid">
|
||||
<div class="invalid-feedback">Please enter a UUID for this profile.</div>
|
||||
</div>
|
||||
<div purpose="modal-form-option" v-if="selectedPlatform === 'android'">
|
||||
<label for="profile-version">Version</label>
|
||||
<input type="text" :class="[formErrors.version ? 'is-invalid' : '']" class="form-control" id="version" v-model="downloadProfileFormData.version">
|
||||
<div class="invalid-feedback">Please enter a version for this profile.</div>
|
||||
</div>
|
||||
<div purpose="modal-form-option" v-if="selectedPlatform === 'macos'">
|
||||
<label for="profile-description">Description <img style="margin-left: 6px; height: 14px" class="d-inline" purpose="tooltip-icon" src="/images/icon-more-info-14x14@2x.png" alt="More info" data-toggle="tooltip" tabindex="0" data-placement="top" title="A unique identifier for this payload, used to track and update the payload during profile replacements. Must be globally unique."></label>
|
||||
<textarea class="form-control" id="description" v-model="downloadProfileFormData.description"></textarea>
|
||||
|
|
|
|||
Loading…
Reference in a new issue