Add suport for accessibility service permission

This commit is contained in:
Jonas L 2019-03-25 00:00:00 +00:00
parent b6f5edc976
commit 0e601995ec
10 changed files with 117 additions and 9 deletions

View file

@ -26,13 +26,14 @@ export class IgnoreManipulationAction extends ParentAction {
readonly ignoreNotificationAccessManipulation: boolean
readonly ignoreUsageStatsAccessManipulation: boolean
readonly ignoreOverlayPermissionManipulation: boolean
readonly ignoreAccessibilityServiceManipulation: boolean
readonly ignoreDidReboot: boolean
readonly ignoreHadManipulation: boolean
constructor ({
deviceId, ignoreDeviceAdminManipulation, ignoreDeviceAdminManipulationAttempt,
ignoreAppDowngrade, ignoreNotificationAccessManipulation, ignoreUsageStatsAccessManipulation,
ignoreOverlayPermissionManipulation, ignoreDidReboot, ignoreHadManipulation
ignoreOverlayPermissionManipulation, ignoreAccessibilityServiceManipulation, ignoreDidReboot, ignoreHadManipulation
}: {
deviceId: string
ignoreDeviceAdminManipulation: boolean
@ -41,6 +42,7 @@ export class IgnoreManipulationAction extends ParentAction {
ignoreNotificationAccessManipulation: boolean
ignoreUsageStatsAccessManipulation: boolean
ignoreOverlayPermissionManipulation: boolean
ignoreAccessibilityServiceManipulation: boolean
ignoreDidReboot: boolean
ignoreHadManipulation: boolean
}) {
@ -55,6 +57,7 @@ export class IgnoreManipulationAction extends ParentAction {
this.ignoreNotificationAccessManipulation = ignoreNotificationAccessManipulation
this.ignoreUsageStatsAccessManipulation = ignoreUsageStatsAccessManipulation
this.ignoreOverlayPermissionManipulation = ignoreOverlayPermissionManipulation
this.ignoreAccessibilityServiceManipulation = ignoreAccessibilityServiceManipulation
this.ignoreDidReboot = ignoreDidReboot
this.ignoreHadManipulation = ignoreHadManipulation
}
@ -67,11 +70,12 @@ export class IgnoreManipulationAction extends ParentAction {
downgrade: this.ignoreAppDowngrade,
notification: this.ignoreNotificationAccessManipulation,
overlay: this.ignoreOverlayPermissionManipulation,
accessibilityService: this.ignoreAccessibilityServiceManipulation,
usageStats: this.ignoreUsageStatsAccessManipulation,
hadManipulation: this.ignoreHadManipulation
})
static parse = ({ deviceId, admin, adminA, downgrade, notification, usageStats, overlay, reboot, hadManipulation }: SerializedIgnoreManipulationAction) => (
static parse = ({ deviceId, admin, adminA, downgrade, notification, usageStats, overlay, accessibilityService, reboot, hadManipulation }: SerializedIgnoreManipulationAction) => (
new IgnoreManipulationAction({
deviceId,
ignoreDeviceAdminManipulation: admin,
@ -80,6 +84,7 @@ export class IgnoreManipulationAction extends ParentAction {
ignoreUsageStatsAccessManipulation: usageStats,
ignoreNotificationAccessManipulation: notification,
ignoreOverlayPermissionManipulation: !!overlay,
ignoreAccessibilityServiceManipulation: !!accessibilityService,
ignoreDidReboot: !!reboot,
ignoreHadManipulation: hadManipulation
})
@ -98,4 +103,5 @@ export interface SerializedIgnoreManipulationAction {
// was added at a later version
reboot?: boolean
overlay?: boolean
accessibilityService?: boolean
}

View file

@ -25,14 +25,16 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
readonly newUsageStatsPermissionStatus?: RuntimePermissionStatus
readonly newNotificationAccessPermission?: NewPermissionStatus
readonly newOverlayPermission?: RuntimePermissionStatus
readonly newAccessibilityServiceEnabled?: boolean
readonly newAppVersion?: number
readonly didReboot: boolean
constructor ({ newProtetionLevel, newUsageStatsPermissionStatus, newNotificationAccessPermission, newOverlayPermission, newAppVersion, didReboot }: {
constructor ({ newProtetionLevel, newUsageStatsPermissionStatus, newNotificationAccessPermission, newOverlayPermission, newAccessibilityServiceEnabled, newAppVersion, didReboot }: {
newProtetionLevel?: ProtectionLevel
newUsageStatsPermissionStatus?: RuntimePermissionStatus
newNotificationAccessPermission?: NewPermissionStatus
newOverlayPermission?: RuntimePermissionStatus
newAccessibilityServiceEnabled?: boolean
newAppVersion?: number
didReboot: boolean
}) {
@ -48,6 +50,7 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
this.newUsageStatsPermissionStatus = newUsageStatsPermissionStatus
this.newNotificationAccessPermission = newNotificationAccessPermission
this.newOverlayPermission = newOverlayPermission
this.newAccessibilityServiceEnabled = newAccessibilityServiceEnabled
this.newAppVersion = newAppVersion
this.didReboot = didReboot
}
@ -58,16 +61,18 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
usageStats: this.newUsageStatsPermissionStatus,
notificationAccess: this.newNotificationAccessPermission,
overlayPermission: this.newOverlayPermission,
accessibilityServiceEnabled: this.newAccessibilityServiceEnabled,
appVersion: this.newAppVersion,
didReboot: this.didReboot
})
static parse = ({ protectionLevel, usageStats, notificationAccess, overlayPermission, appVersion, didReboot }: SerializedUpdateDeviceStatusAction) => (
static parse = ({ protectionLevel, usageStats, notificationAccess, overlayPermission, accessibilityServiceEnabled, appVersion, didReboot }: SerializedUpdateDeviceStatusAction) => (
new UpdateDeviceStatusAction({
newProtetionLevel: protectionLevel,
newUsageStatsPermissionStatus: usageStats,
newNotificationAccessPermission: notificationAccess,
newOverlayPermission: overlayPermission,
newAccessibilityServiceEnabled: accessibilityServiceEnabled,
newAppVersion: appVersion,
didReboot: !!didReboot
})
@ -80,6 +85,7 @@ export interface SerializedUpdateDeviceStatusAction {
usageStats?: RuntimePermissionStatus
notificationAccess?: NewPermissionStatus
overlayPermission?: RuntimePermissionStatus
accessibilityServiceEnabled?: boolean
appVersion?: number
didReboot?: boolean
}

View file

@ -336,6 +336,9 @@ const definitions = {
},
"overlay": {
"type": "boolean"
},
"accessibilityService": {
"type": "boolean"
}
},
"additionalProperties": false,
@ -1123,6 +1126,9 @@ const definitions = {
],
"type": "string"
},
"accessibilityServiceEnabled": {
"type": "boolean"
},
"appVersion": {
"type": "number"
},

View file

@ -74,9 +74,15 @@ export interface DeviceAttributesVersion7 {
highestOverlayPermission: RuntimePermissionStatus
}
export interface DeviceAttributesVersion8 {
// as = accessibility service
asEnabled: boolean
wasAsEnabled: boolean
}
export type DeviceAttributes = DeviceAttributesVersion1 & DeviceAttributesVersion2 &
DeviceAttributesVersion3 & DeviceAttributesVersion4 & DeviceAttributesVersion5 &
DeviceAttributesVersion6 & DeviceAttributesVersion7
DeviceAttributesVersion6 & DeviceAttributesVersion7 & DeviceAttributesVersion8
export type DeviceInstance = Sequelize.Instance<DeviceAttributes> & DeviceAttributes
export type DeviceModel = Sequelize.Model<DeviceInstance, DeviceAttributes>
@ -191,6 +197,17 @@ export const attributesVersion7: SequelizeAttributes<DeviceAttributesVersion7> =
}
}
export const attributesVersion8: SequelizeAttributes<DeviceAttributesVersion8> = {
asEnabled: {
...booleanColumn,
defaultValue: false
},
wasAsEnabled: {
...booleanColumn,
defaultValue: false
}
}
export const attributes: SequelizeAttributes<DeviceAttributes> = {
...attributesVersion1,
...attributesVersion2,
@ -198,7 +215,8 @@ export const attributes: SequelizeAttributes<DeviceAttributes> = {
...attributesVersion4,
...attributesVersion5,
...attributesVersion6,
...attributesVersion7
...attributesVersion7,
...attributesVersion8
}
export const createDeviceModel = (sequelize: Sequelize.Sequelize): DeviceModel => sequelize.define<DeviceInstance, DeviceAttributes>('Device', attributes)
@ -208,6 +226,7 @@ export const hasDeviceManipulation = (device: DeviceAttributes) => {
const manipulationOfNotificationAccess = device.currentNotificationAccessPermission !== device.highestNotificationAccessPermission
const manipulationOfAppVersion = device.currentAppVersion !== device.highestAppVersion
const manipulationOfOverlayPermission = device.currentOverlayPermission !== device.highestOverlayPermission
const manipulationOfAsPermission = device.asEnabled !== device.wasAsEnabled
const hasActiveManipulationWarning = manipulationOfProtectionLevel ||
manipulationOfUsageStats ||
@ -215,7 +234,8 @@ export const hasDeviceManipulation = (device: DeviceAttributes) => {
manipulationOfAppVersion ||
device.triedDisablingDeviceAdmin ||
device.didReboot ||
manipulationOfOverlayPermission
manipulationOfOverlayPermission ||
manipulationOfAsPermission
const hasAnyManipulation = hasActiveManipulationWarning || device.hadManipulation

View file

@ -0,0 +1,46 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { QueryInterface, Sequelize } from 'sequelize'
import { attributesVersion8 } from '../../device'
export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
await sequelize.transaction({
type: 'EXCLUSIVE'
}, async (transaction) => {
await queryInterface.addColumn('Devices', 'asEnabled', {
...attributesVersion8.asEnabled
}, {
transaction
})
await queryInterface.addColumn('Devices', 'wasAsEnabled', {
...attributesVersion8.wasAsEnabled
}, {
transaction
})
})
}
export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
await sequelize.transaction({
type: 'EXCLUSIVE'
}, async (transaction) => {
await queryInterface.removeColumn('Devices', 'asEnabled', { transaction })
await queryInterface.removeColumn('Devices', 'wasAsEnabled', { transaction })
})
}

View file

@ -57,5 +57,7 @@ export const prepareDeviceEntry = ({ familyId, userId, deviceAuthToken, deviceId
defaultUserTimeout: 0,
considerRebootManipulation: false,
currentOverlayPermission: 'not granted',
highestOverlayPermission: 'not granted'
highestOverlayPermission: 'not granted',
asEnabled: false,
wasAsEnabled: false
})

View file

@ -107,6 +107,20 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
}
}
if (action.newAccessibilityServiceEnabled !== undefined) {
const hasChanged = deviceEntry.asEnabled !== action.newAccessibilityServiceEnabled
deviceEntry.asEnabled = action.newAccessibilityServiceEnabled
if (action.newAccessibilityServiceEnabled) {
deviceEntry.wasAsEnabled = true
}
if (hasChanged && (deviceEntry.asEnabled !== deviceEntry.wasAsEnabled)) {
deviceEntry.hadManipulation = true
}
}
if (action.newAppVersion !== undefined) {
const hasChanged = deviceEntry.currentAppVersion !== action.newAppVersion

View file

@ -58,6 +58,10 @@ export async function dispatchIgnoreManipulation ({ action, cache }: {
deviceEntry.highestOverlayPermission = deviceEntry.currentOverlayPermission
}
if (action.ignoreAccessibilityServiceManipulation) {
deviceEntry.wasAsEnabled = deviceEntry.asEnabled
}
if (action.ignoreDidReboot) {
deviceEntry.didReboot = false
}

View file

@ -95,7 +95,9 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
defUserTimeout: item.defaultUserTimeout,
rebootIsManipulation: item.considerRebootManipulation,
cOverlay: item.currentOverlayPermission,
hOverlay: item.highestOverlayPermission
hOverlay: item.highestOverlayPermission,
asEnabled: item.asEnabled,
wasAsEnabled: item.wasAsEnabled
}))
}
}

View file

@ -84,6 +84,8 @@ export interface ServerDeviceData {
rebootIsManipulation: boolean
cOverlay: RuntimePermissionStatus
hOverlay: RuntimePermissionStatus
asEnabled: boolean
wasAsEnabled: boolean
}
export interface ServerUpdatedCategoryBaseData {