/* * Copyright 2019 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package im.vector.matrix.android.api.pushrules import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.internal.di.MoshiProvider import timber.log.Timber class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind.event_match) { override fun isSatisfied(conditionResolver: ConditionResolver) : Boolean { return conditionResolver.resolveEventMatchCondition(this) } override fun technicalDescription(): String { return "'$key' Matches '$pattern'" } fun isSatisfied(event: Event): Boolean { //TODO encrypted events? val rawJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJsonValue(event) as? Map<*, *> ?: return false val value = extractField(rawJson, key) ?: return false //Patterns with no special glob characters should be treated as having asterisks prepended // and appended when testing the condition. try { val modPattern = if (hasSpecialGlobChar(pattern)) simpleGlobToRegExp(pattern) else simpleGlobToRegExp("*$pattern*") val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL) return regex.containsMatchIn(value) } catch (e: Throwable) { //e.g PatternSyntaxException Timber.e(e, "Failed to evaluate push condition") return false } } private fun extractField(jsonObject: Map<*, *>, fieldPath: String): String? { val fieldParts = fieldPath.split(".") if (fieldParts.isEmpty()) return null var jsonElement: Map<*, *> = jsonObject fieldParts.forEachIndexed { index, pathSegment -> if (index == fieldParts.lastIndex) { return jsonElement[pathSegment]?.toString() } else { val sub = jsonElement[pathSegment] ?: return null if (sub is Map<*, *>) { jsonElement = sub } else { return null } } } return null } companion object { private fun hasSpecialGlobChar(glob: String): Boolean { return glob.contains("*") || glob.contains("?") } //Very simple glob to regexp converter private fun simpleGlobToRegExp(glob: String): String { var out = ""//"^" for (i in 0 until glob.length) { val c = glob[i] when (c) { '*' -> out += ".*" '?' -> out += '.'.toString() '.' -> out += "\\." '\\' -> out += "\\\\" else -> out += c } } out += ""//'$'.toString() return out } } }