diff --git a/src/action/ignoremanipulation.ts b/src/action/ignoremanipulation.ts
index 7b10259..0db329a 100644
--- a/src/action/ignoremanipulation.ts
+++ b/src/action/ignoremanipulation.ts
@@ -15,6 +15,7 @@
* along with this program. If not, see .
*/
+import { DeviceHadManipulationFlags } from '../database/device'
import { assertIdWithinFamily } from '../util/token'
import { ParentAction } from './basetypes'
@@ -29,11 +30,12 @@ export class IgnoreManipulationAction extends ParentAction {
readonly ignoreAccessibilityServiceManipulation: boolean
readonly ignoreDidReboot: boolean
readonly ignoreHadManipulation: boolean
+ readonly ignoreHadManipulationFlags: number
constructor ({
deviceId, ignoreDeviceAdminManipulation, ignoreDeviceAdminManipulationAttempt,
ignoreAppDowngrade, ignoreNotificationAccessManipulation, ignoreUsageStatsAccessManipulation,
- ignoreOverlayPermissionManipulation, ignoreAccessibilityServiceManipulation, ignoreDidReboot, ignoreHadManipulation
+ ignoreOverlayPermissionManipulation, ignoreAccessibilityServiceManipulation, ignoreDidReboot, ignoreHadManipulation, ignoreHadManipulationFlags
}: {
deviceId: string
ignoreDeviceAdminManipulation: boolean
@@ -45,11 +47,19 @@ export class IgnoreManipulationAction extends ParentAction {
ignoreAccessibilityServiceManipulation: boolean
ignoreDidReboot: boolean
ignoreHadManipulation: boolean
+ ignoreHadManipulationFlags: number
}) {
super()
assertIdWithinFamily(deviceId)
+ if (
+ (!Number.isSafeInteger(ignoreHadManipulationFlags)) ||
+ ignoreHadManipulationFlags < 0 || ignoreHadManipulationFlags > DeviceHadManipulationFlags.ALL
+ ) {
+ throw new Error('invalid ignoreHadManipulationFlags')
+ }
+
this.deviceId = deviceId
this.ignoreDeviceAdminManipulation = ignoreDeviceAdminManipulation
this.ignoreDeviceAdminManipulationAttempt = ignoreDeviceAdminManipulationAttempt
@@ -60,6 +70,7 @@ export class IgnoreManipulationAction extends ParentAction {
this.ignoreAccessibilityServiceManipulation = ignoreAccessibilityServiceManipulation
this.ignoreDidReboot = ignoreDidReboot
this.ignoreHadManipulation = ignoreHadManipulation
+ this.ignoreHadManipulationFlags = ignoreHadManipulationFlags
}
serialize = (): SerializedIgnoreManipulationAction => ({
@@ -72,10 +83,11 @@ export class IgnoreManipulationAction extends ParentAction {
overlay: this.ignoreOverlayPermissionManipulation,
accessibilityService: this.ignoreAccessibilityServiceManipulation,
usageStats: this.ignoreUsageStatsAccessManipulation,
- hadManipulation: this.ignoreHadManipulation
+ hadManipulation: this.ignoreHadManipulation,
+ ignoreHadManipulationFlags: this.ignoreHadManipulationFlags
})
- static parse = ({ deviceId, admin, adminA, downgrade, notification, usageStats, overlay, accessibilityService, reboot, hadManipulation }: SerializedIgnoreManipulationAction) => (
+ static parse = ({ deviceId, admin, adminA, downgrade, notification, usageStats, overlay, accessibilityService, reboot, hadManipulation, ignoreHadManipulationFlags }: SerializedIgnoreManipulationAction) => (
new IgnoreManipulationAction({
deviceId,
ignoreDeviceAdminManipulation: admin,
@@ -86,7 +98,8 @@ export class IgnoreManipulationAction extends ParentAction {
ignoreOverlayPermissionManipulation: !!overlay,
ignoreAccessibilityServiceManipulation: !!accessibilityService,
ignoreDidReboot: !!reboot,
- ignoreHadManipulation: hadManipulation
+ ignoreHadManipulation: hadManipulation,
+ ignoreHadManipulationFlags: ignoreHadManipulationFlags || 0
})
)
}
@@ -104,4 +117,5 @@ export interface SerializedIgnoreManipulationAction {
reboot?: boolean
overlay?: boolean
accessibilityService?: boolean
+ ignoreHadManipulationFlags?: number
}
diff --git a/src/api/validator.ts b/src/api/validator.ts
index d158389..7f4fbb8 100644
--- a/src/api/validator.ts
+++ b/src/api/validator.ts
@@ -339,6 +339,9 @@ const definitions = {
},
"accessibilityService": {
"type": "boolean"
+ },
+ "ignoreHadManipulationFlags": {
+ "type": "number"
}
},
"additionalProperties": false,
diff --git a/src/database/device.ts b/src/database/device.ts
index 3b5ad9b..ba299ec 100644
--- a/src/database/device.ts
+++ b/src/database/device.ts
@@ -22,6 +22,16 @@ import { RuntimePermissionStatus, runtimePermissionStatusValues } from '../model
import { authTokenColumn, booleanColumn, createEnumColumn, familyIdColumn, idWithinFamilyColumn, labelColumn, optionalIdWithinFamilyColumn, timestampColumn, versionColumn } from './columns'
import { SequelizeAttributes } from './types'
+export const DeviceHadManipulationFlags = {
+ ProtectionLevel: 1,
+ UsageStatsAccess: 2,
+ NotificationAccess: 4,
+ AppVersion: 8,
+ OverlayPermission: 16,
+ AccessibiityService: 32,
+ ALL: 1 | 2 | 4 | 8 | 16 | 32
+}
+
export interface DeviceAttributesVersion1 {
familyId: string
deviceId: string
@@ -88,10 +98,14 @@ export interface DeviceAttributesVersion10 {
isQorLater: boolean
}
+export interface DeviceAttributesVersion11 {
+ hadManipulationFlags: number
+}
+
export type DeviceAttributes = DeviceAttributesVersion1 & DeviceAttributesVersion2 &
DeviceAttributesVersion3 & DeviceAttributesVersion4 & DeviceAttributesVersion5 &
DeviceAttributesVersion6 & DeviceAttributesVersion7 & DeviceAttributesVersion8 &
- DeviceAttributesVersion9 & DeviceAttributesVersion10
+ DeviceAttributesVersion9 & DeviceAttributesVersion10 & DeviceAttributesVersion11
export type DeviceModel = Sequelize.Model & DeviceAttributes
export type DeviceModelStatic = typeof Sequelize.Model & {
@@ -233,6 +247,18 @@ export const attributesVersion10: SequelizeAttributes
}
}
+export const attributesVersion11: SequelizeAttributes = {
+ hadManipulationFlags: {
+ type: Sequelize.INTEGER,
+ allowNull: false,
+ defaultValue: 0,
+ validate: {
+ min: 0,
+ max: DeviceHadManipulationFlags.ALL
+ }
+ }
+}
+
export const attributes: SequelizeAttributes = {
...attributesVersion1,
...attributesVersion2,
@@ -243,7 +269,8 @@ export const attributes: SequelizeAttributes = {
...attributesVersion7,
...attributesVersion8,
...attributesVersion9,
- ...attributesVersion10
+ ...attributesVersion10,
+ ...attributesVersion11
}
export const createDeviceModel = (sequelize: Sequelize.Sequelize): DeviceModelStatic => sequelize.define('Device', attributes) as DeviceModelStatic
diff --git a/src/database/migration/migrations/20190805-add-had-manipulation-flags.ts b/src/database/migration/migrations/20190805-add-had-manipulation-flags.ts
new file mode 100644
index 0000000..6c64a30
--- /dev/null
+++ b/src/database/migration/migrations/20190805-add-had-manipulation-flags.ts
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion11 as deviceAttributes } from '../../device'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Devices', 'hadManipulationFlags', {
+ ...deviceAttributes.hadManipulationFlags
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Devices', 'hadManipulationFlags', { transaction })
+ })
+}
diff --git a/src/function/device/prepare-device-entry.ts b/src/function/device/prepare-device-entry.ts
index 36b35a5..e0c9edc 100644
--- a/src/function/device/prepare-device-entry.ts
+++ b/src/function/device/prepare-device-entry.ts
@@ -48,6 +48,7 @@ export const prepareDeviceEntry = ({ familyId, userId, deviceAuthToken, deviceId
triedDisablingDeviceAdmin: false,
didReboot: false,
hadManipulation: false,
+ hadManipulationFlags: 0,
lastConnectivity: '0',
notSeenForLongTime: false,
didDeviceReportUninstall: false,
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts
index 444c345..520ea0c 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts
@@ -16,7 +16,7 @@
*/
import { UpdateDeviceStatusAction } from '../../../../action'
-import { hasDeviceManipulation } from '../../../../database/device'
+import { DeviceHadManipulationFlags, hasDeviceManipulation } from '../../../../database/device'
import { newPermissionStatusValues } from '../../../../model/newpermissionstatus'
import { protetionLevels } from '../../../../model/protectionlevel'
import { runtimePermissionStatusValues } from '../../../../model/runtimepermissionstatus'
@@ -56,6 +56,7 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
if (hasChanged && (deviceEntry.currentProtectionLevel !== deviceEntry.highestProtectionLevel)) {
deviceEntry.hadManipulation = true
+ deviceEntry.hadManipulationFlags |= DeviceHadManipulationFlags.ProtectionLevel
}
}
@@ -72,6 +73,7 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
if (hasChanged && (deviceEntry.currentUsageStatsPermission !== deviceEntry.highestUsageStatsPermission)) {
deviceEntry.hadManipulation = true
+ deviceEntry.hadManipulationFlags |= DeviceHadManipulationFlags.UsageStatsAccess
}
}
@@ -88,6 +90,7 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
if (hasChanged && (deviceEntry.currentNotificationAccessPermission !== deviceEntry.highestNotificationAccessPermission)) {
deviceEntry.hadManipulation = true
+ deviceEntry.hadManipulationFlags |= DeviceHadManipulationFlags.NotificationAccess
}
}
@@ -104,6 +107,7 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
if (hasChanged && (deviceEntry.currentOverlayPermission !== deviceEntry.highestOverlayPermission)) {
deviceEntry.hadManipulation = true
+ deviceEntry.hadManipulationFlags |= DeviceHadManipulationFlags.OverlayPermission
}
}
@@ -118,6 +122,7 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
if (hasChanged && (deviceEntry.asEnabled !== deviceEntry.wasAsEnabled)) {
deviceEntry.hadManipulation = true
+ deviceEntry.hadManipulationFlags |= DeviceHadManipulationFlags.AccessibiityService
}
}
@@ -133,6 +138,7 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
if (hasChanged && (deviceEntry.currentAppVersion !== deviceEntry.highestAppVersion)) {
deviceEntry.hadManipulation = true
+ deviceEntry.hadManipulationFlags |= DeviceHadManipulationFlags.AppVersion
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts b/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts
index 10b35fd..b16a646 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts
@@ -70,6 +70,16 @@ export async function dispatchIgnoreManipulation ({ action, cache }: {
deviceEntry.hadManipulation = false
}
+ if (action.ignoreHadManipulationFlags !== 0) {
+ const newFlags = deviceEntry.hadManipulationFlags & (~action.ignoreHadManipulationFlags)
+
+ deviceEntry.hadManipulationFlags = newFlags
+
+ if (newFlags === 0) {
+ deviceEntry.hadManipulation = false
+ }
+ }
+
await deviceEntry.save({ transaction: cache.transaction })
cache.invalidiateDeviceList = true
}
diff --git a/src/function/sync/get-server-data-status.ts b/src/function/sync/get-server-data-status.ts
index 2a128e9..414e55b 100644
--- a/src/function/sync/get-server-data-status.ts
+++ b/src/function/sync/get-server-data-status.ts
@@ -89,6 +89,7 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
tDisablingAdmin: item.triedDisablingDeviceAdmin,
reboot: item.didReboot,
hadManipulation: item.hadManipulation,
+ hadManipulationFlags: item.hadManipulationFlags,
reportUninstall: item.didDeviceReportUninstall,
isUserKeptSignedIn: item.isUserKeptSignedIn,
showDeviceConnected: item.showDeviceConnected,
diff --git a/src/object/serverdatastatus.ts b/src/object/serverdatastatus.ts
index b3580ab..7c8ab5f 100644
--- a/src/object/serverdatastatus.ts
+++ b/src/object/serverdatastatus.ts
@@ -77,6 +77,7 @@ export interface ServerDeviceData {
tDisablingAdmin: boolean
reboot: boolean
hadManipulation: boolean
+ hadManipulationFlags: number
reportUninstall: boolean
isUserKeptSignedIn: boolean
showDeviceConnected: boolean