Search in sources :

Example 1 with StoredPacketGroup

use of me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup in project solarthing by wildmountainfarms.

the class AlterManagerAction method onUpdate.

@Override
protected void onUpdate() {
    super.onUpdate();
    // Supply queried solarthing_open packets to the security packet receiver, which may execute code to put commands requested to be scheduled in solarthing_alter
    List<StoredPacketGroup> packets = openDatabaseCache.getAllCachedPackets();
    securityPacketReceiver.receivePacketGroups(packets);
    // Check packets in solarthing_alter and see if we need to send a command because of a scheduled command packet
    Instant now = Instant.now();
    List<VersionedPacket<StoredAlterPacket>> alterPackets = alterPacketsProvider.getPackets();
    if (alterPackets == null) {
        LOGGER.info("alterPackets is null. Maybe query failed? Maybe additional info in previous logs?");
    } else {
        for (VersionedPacket<StoredAlterPacket> versionedPacket : alterPackets) {
            AlterPacket packet = versionedPacket.getPacket().getPacket();
            if (packet instanceof ScheduledCommandPacket) {
                ScheduledCommandPacket scheduledCommandPacket = (ScheduledCommandPacket) packet;
                ScheduledCommandData data = scheduledCommandPacket.getData();
                if (data.getScheduledTimeMillis() <= now.toEpochMilli()) {
                    if (now.toEpochMilli() - data.getScheduledTimeMillis() > Duration.ofMinutes(5).toMillis()) {
                        LOGGER.warn("Not going to send a command scheduled for more than 5 minutes ago! data: " + data);
                    } else {
                        doSendCommand(versionedPacket, scheduledCommandPacket);
                    }
                }
            } else if (packet instanceof FlagPacket) {
                FlagPacket flagPacket = (FlagPacket) packet;
                FlagData data = flagPacket.getFlagData();
                ActivePeriod activePeriod = data.getActivePeriod();
                if (activePeriod instanceof TimeRangeActivePeriod) {
                    // We only try to "manage" flags that use this type of ActivePeriod
                    TimeRangeActivePeriod period = (TimeRangeActivePeriod) activePeriod;
                    TimeRange timeRange = period.getTimeRange();
                    Instant endTime = timeRange.getEndTime();
                    if (endTime != null && endTime.compareTo(now) < 0) {
                        // If there is an end time, and it is in the past, then we should remove the flag
                        executorService.execute(() -> {
                            try {
                                database.getAlterDatabase().delete(versionedPacket);
                            } catch (SolarThingDatabaseException e) {
                                LOGGER.error("Could not delete a FlagPacket with an expired time", e);
                            // If we cannot delete it, no need to try again, it'll still be here next time around
                            }
                        });
                    }
                }
            }
        }
    }
}
Also used : FlagPacket(me.retrodaredevil.solarthing.type.alter.packets.FlagPacket) RequestFlagPacket(me.retrodaredevil.solarthing.commands.packets.open.RequestFlagPacket) ImmutableStoredAlterPacket(me.retrodaredevil.solarthing.type.alter.ImmutableStoredAlterPacket) StoredAlterPacket(me.retrodaredevil.solarthing.type.alter.StoredAlterPacket) Instant(java.time.Instant) VersionedPacket(me.retrodaredevil.solarthing.database.VersionedPacket) ActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.ActivePeriod) TimeRangeActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.TimeRangeActivePeriod) ImmutableStoredAlterPacket(me.retrodaredevil.solarthing.type.alter.ImmutableStoredAlterPacket) DeleteAlterPacket(me.retrodaredevil.solarthing.commands.packets.open.DeleteAlterPacket) StoredAlterPacket(me.retrodaredevil.solarthing.type.alter.StoredAlterPacket) AlterPacket(me.retrodaredevil.solarthing.type.alter.AlterPacket) TimeRangeActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.TimeRangeActivePeriod) UpdateConflictSolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.UpdateConflictSolarThingDatabaseException) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException) TimeRange(me.retrodaredevil.solarthing.util.TimeRange) ScheduledCommandPacket(me.retrodaredevil.solarthing.type.alter.packets.ScheduledCommandPacket) FlagData(me.retrodaredevil.solarthing.type.alter.flag.FlagData) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) ScheduledCommandData(me.retrodaredevil.solarthing.type.alter.packets.ScheduledCommandData)

Example 2 with StoredPacketGroup

use of me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup in project solarthing by wildmountainfarms.

the class CouchDbMillisDatabase method query.

@Override
public List<StoredPacketGroup> query(MillisQuery query) throws SolarThingDatabaseException {
    final ViewResponse response;
    try {
        response = database.queryView(SolarThingCouchDb.createMillisNullView(CouchDbQueryUtil.createMillisNullParams(query)));
    } catch (CouchDbException e) {
        throw ExceptionUtil.createFromCouchDbException(e);
    }
    List<ViewResponse.DocumentEntry> rows = response.getRows();
    List<StoredPacketGroup> r = new ArrayList<>(rows.size());
    for (ViewResponse.DocumentEntry row : rows) {
        // When using includeDocs=true, we want to use the doc, not its value (which is null with millisNull)
        JsonData jsonData = row.getDoc();
        StoredPacketGroup storedPacketGroup = jsonDataToStoredPacketGroup(jsonData).getPacket();
        r.add(storedPacketGroup);
    }
    return r;
}
Also used : CouchDbException(me.retrodaredevil.couchdbjava.exception.CouchDbException) ViewResponse(me.retrodaredevil.couchdbjava.response.ViewResponse) ArrayList(java.util.ArrayList) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) JsonData(me.retrodaredevil.couchdbjava.json.JsonData) StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData)

Example 3 with StoredPacketGroup

use of me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup in project solarthing by wildmountainfarms.

the class AlterManagerAction method isDocumentMadeByUs.

private boolean isDocumentMadeByUs(Instant now, ScheduledCommandData scheduledCommandData, StoredPacketGroup existingDocument) {
    LargeIntegrityPacket largeIntegrityPacket = (LargeIntegrityPacket) existingDocument.getPackets().stream().filter(p -> p instanceof LargeIntegrityPacket).findAny().orElse(null);
    if (largeIntegrityPacket == null) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The stored document did not have a LargeIntegrity packet. Someone must be trying to stop a scheduled command!");
        return false;
    }
    String sender = largeIntegrityPacket.getSender();
    if (!commandManager.getSender().equals(sender)) {
        LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "The sender of the large integrity packet we are inspecting is not us (" + commandManager.getSender() + "). It is " + sender + ". Might be a malicious actor, might be a bad setup.");
        return false;
    }
    String encryptedHash = largeIntegrityPacket.getEncryptedHash();
    String data;
    try {
        synchronized (CIPHER) {
            data = Decrypt.decrypt(CIPHER, commandManager.getKeyPair().getPublic(), encryptedHash);
        }
    } catch (InvalidKeyException e) {
        throw new RuntimeException("Should be a valid key!", e);
    } catch (DecryptException e) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The document we are inspecting had a large integrity packet with the sender: " + sender + ", but that's us and we couldn't decrypt their payload. Likely a malicious actor", e);
        return false;
    }
    final String[] split = data.split(",", 2);
    LOGGER.debug("decrypted data: " + data);
    if (split.length != 2) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "split.length: " + split.length + " split: " + Arrays.asList(split));
        return false;
    }
    String hexMillis = split[0];
    // String message = split[1]; We don't care what the message is. We don't even care enough to check if it matches the payload's hash
    long dateMillis;
    try {
        dateMillis = Long.parseLong(hexMillis, 16);
    } catch (NumberFormatException e) {
        LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "Error parsing hex date millis", e);
        return false;
    }
    if (dateMillis < scheduledCommandData.getScheduledTimeMillis()) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The dateMillis for this is less than the command's scheduled execution time! This must be a malicious actor!");
        return false;
    }
    if (dateMillis > now.toEpochMilli()) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The dateMillis for this is greater than now! This should never ever happen.");
        return false;
    }
    return true;
}
Also used : CommandManager(me.retrodaredevil.solarthing.commands.util.CommandManager) Packet(me.retrodaredevil.solarthing.packets.Packet) Arrays(java.util.Arrays) AlterPacketsProvider(me.retrodaredevil.solarthing.AlterPacketsProvider) LoggerFactory(org.slf4j.LoggerFactory) InstanceTargetPackets(me.retrodaredevil.solarthing.packets.instance.InstanceTargetPackets) VersionedPacket(me.retrodaredevil.solarthing.database.VersionedPacket) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket) ActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.ActivePeriod) ImmutableStoredAlterPacket(me.retrodaredevil.solarthing.type.alter.ImmutableStoredAlterPacket) DeleteAlterPacket(me.retrodaredevil.solarthing.commands.packets.open.DeleteAlterPacket) InvalidKeyException(me.retrodaredevil.solarthing.packets.security.crypto.InvalidKeyException) Duration(java.time.Duration) FlagPacket(me.retrodaredevil.solarthing.type.alter.packets.FlagPacket) RequestCommandPacket(me.retrodaredevil.solarthing.commands.packets.open.RequestCommandPacket) DecryptException(me.retrodaredevil.solarthing.packets.security.crypto.DecryptException) Instant(java.time.Instant) IncompatibleUpdateTokenException(me.retrodaredevil.solarthing.database.exception.IncompatibleUpdateTokenException) ZoneId(java.time.ZoneId) Executors(java.util.concurrent.Executors) ExecutionReason(me.retrodaredevil.solarthing.reason.ExecutionReason) List(java.util.List) SolarThingConstants(me.retrodaredevil.solarthing.SolarThingConstants) TimeRange(me.retrodaredevil.solarthing.util.TimeRange) TimeRangeActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.TimeRangeActivePeriod) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ScheduledCommandPacket(me.retrodaredevil.solarthing.type.alter.packets.ScheduledCommandPacket) OpenSource(me.retrodaredevil.solarthing.type.open.OpenSource) TargetPacketGroup(me.retrodaredevil.solarthing.packets.collection.TargetPacketGroup) Cipher(javax.crypto.Cipher) ArrayList(java.util.ArrayList) RequestFlagPacket(me.retrodaredevil.solarthing.commands.packets.open.RequestFlagPacket) FlagData(me.retrodaredevil.solarthing.type.alter.flag.FlagData) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) OpenSourceExecutionReason(me.retrodaredevil.solarthing.reason.OpenSourceExecutionReason) ScheduleCommandPacket(me.retrodaredevil.solarthing.commands.packets.open.ScheduleCommandPacket) ExecutorService(java.util.concurrent.ExecutorService) SimpleAction(me.retrodaredevil.action.SimpleAction) ScheduledCommandData(me.retrodaredevil.solarthing.type.alter.packets.ScheduledCommandData) Logger(org.slf4j.Logger) PacketCollectionCreator(me.retrodaredevil.solarthing.packets.collection.PacketCollectionCreator) KeyUtil(me.retrodaredevil.solarthing.packets.security.crypto.KeyUtil) SolarThingDatabase(me.retrodaredevil.solarthing.database.SolarThingDatabase) Decrypt(me.retrodaredevil.solarthing.packets.security.crypto.Decrypt) DatabaseCache(me.retrodaredevil.solarthing.database.cache.DatabaseCache) StoredAlterPacket(me.retrodaredevil.solarthing.type.alter.StoredAlterPacket) ImmutableRequestCommandPacket(me.retrodaredevil.solarthing.commands.packets.open.ImmutableRequestCommandPacket) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) SecurityPacketReceiver(me.retrodaredevil.solarthing.program.SecurityPacketReceiver) AlterPacket(me.retrodaredevil.solarthing.type.alter.AlterPacket) UpdateConflictSolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.UpdateConflictSolarThingDatabaseException) PublicKeyLookUp(me.retrodaredevil.solarthing.packets.security.crypto.PublicKeyLookUp) Collections(java.util.Collections) PacketCollection(me.retrodaredevil.solarthing.packets.collection.PacketCollection) CommandOpenPacket(me.retrodaredevil.solarthing.commands.packets.open.CommandOpenPacket) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket) InvalidKeyException(me.retrodaredevil.solarthing.packets.security.crypto.InvalidKeyException) DecryptException(me.retrodaredevil.solarthing.packets.security.crypto.DecryptException)

Example 4 with StoredPacketGroup

use of me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup in project solarthing by wildmountainfarms.

the class CouchDbMillisDatabase method jsonDataToStoredPacketGroup.

private VersionedPacket<StoredPacketGroup> jsonDataToStoredPacketGroup(JsonData jsonData) throws SolarThingDatabaseException {
    final JsonNode jsonNode;
    try {
        jsonNode = CouchDbJacksonUtil.getNodeFrom(jsonData);
    } catch (JsonProcessingException e) {
        throw new SolarThingDatabaseException("We couldn't parse some of the data into JSON. This should never happen", e);
    }
    if (!jsonNode.isObject()) {
        throw new SolarThingDatabaseException("Something must be wrong with the packet millis view because we got this jsonNode: " + jsonNode);
    }
    ObjectNode objectNode = (ObjectNode) jsonNode;
    final PacketGroup packetGroup;
    try {
        packetGroup = parser.parse(objectNode);
    } catch (PacketParseException e) {
        throw new SolarThingDatabaseException(e);
    }
    String documentId = objectNode.get("_id").asText();
    String documentRevision = objectNode.get("_rev").asText();
    StoredPacketGroup storedPacketGroup = PacketGroups.createStoredPacketGroup(packetGroup, new CouchDbStoredIdentifier(packetGroup.getDateMillis(), documentId, documentRevision));
    return new VersionedPacket<>(storedPacketGroup, new RevisionUpdateToken(documentRevision));
}
Also used : PacketGroup(me.retrodaredevil.solarthing.packets.collection.PacketGroup) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) VersionedPacket(me.retrodaredevil.solarthing.database.VersionedPacket) PacketParseException(me.retrodaredevil.solarthing.packets.collection.parsing.PacketParseException) JsonNode(com.fasterxml.jackson.databind.JsonNode) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException)

Example 5 with StoredPacketGroup

use of me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup in project solarthing by wildmountainfarms.

the class CommandUtil method getCommandRequesterHandlerList.

/**
 * Gets packet handlers that will download requested commands
 * @param databaseConfigs The list of database configs
 * @param packetGroupReceiver Receives data that has been downloaded. Note that this may be called in a separate thread, so make sure it is thread safe
 * @param options The options object
 * @return A list of packet handlers that, when called, will possibly download commands and then forward those commands to {@code packetGroupReceiver}
 */
public static List<PacketHandler> getCommandRequesterHandlerList(List<DatabaseConfig> databaseConfigs, PacketGroupReceiver packetGroupReceiver, PacketHandlingOption options) {
    // Handlers to request and get new commands to send (This may block the current thread). (This doesn't actually handle packets)
    final List<PacketHandler> commandRequesterHandlerList = new ArrayList<>();
    for (DatabaseConfig config : databaseConfigs) {
        if (CouchDbDatabaseSettings.TYPE.equals(config.getType())) {
            CouchDbDatabaseSettings settings = (CouchDbDatabaseSettings) config.getSettings();
            CouchDbInstance instance = CouchDbUtil.createInstance(settings.getCouchProperties(), settings.getOkHttpProperties());
            SolarThingDatabase database = CouchDbSolarThingDatabase.create(instance);
            IndividualSettings individualSettings = config.getIndividualSettingsOrDefault(Constants.DATABASE_COMMAND_DOWNLOAD_ID, null);
            FrequencySettings frequencySettings = individualSettings != null ? individualSettings.getFrequencySettings() : FrequencySettings.NORMAL_SETTINGS;
            PacketHandler packetHandler = new PacketHandler() {

                private final SecurityPacketReceiver securityPacketReceiver = new SecurityPacketReceiver(DatabaseDocumentKeyMap.createFromDatabase(database), packetGroupReceiver, new SecurityPacketReceiver.InstanceTargetPredicate(options.getSourceId(), options.getFragmentId()), Collections.singleton(CommandOpenPacket.class), System.currentTimeMillis(), options.getFragmentId(), options.getSourceId(), database.getEventDatabase());

                @Override
                public void handle(PacketCollection packetCollection) throws PacketHandleException {
                    final List<StoredPacketGroup> packetGroups;
                    try {
                        packetGroups = database.getOpenDatabase().query(new MillisQueryBuilder().startKey(System.currentTimeMillis() - 5 * 60 * 1000).build());
                    } catch (SolarThingDatabaseException e) {
                        throw new PacketHandleException(e);
                    }
                    securityPacketReceiver.receivePacketGroups(packetGroups);
                }
            };
            commandRequesterHandlerList.add(new ThrottleFactorPacketHandler(new AsyncPacketHandlerWrapper(new PrintPacketHandleExceptionWrapper(packetHandler)), frequencySettings));
        }
    }
    return commandRequesterHandlerList;
}
Also used : PacketCollection(me.retrodaredevil.solarthing.packets.collection.PacketCollection) ArrayList(java.util.ArrayList) MillisQueryBuilder(me.retrodaredevil.solarthing.database.MillisQueryBuilder) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException) CouchDbDatabaseSettings(me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) CouchDbInstance(me.retrodaredevil.couchdbjava.CouchDbInstance) CouchDbSolarThingDatabase(me.retrodaredevil.solarthing.database.couchdb.CouchDbSolarThingDatabase) SolarThingDatabase(me.retrodaredevil.solarthing.database.SolarThingDatabase) IndividualSettings(me.retrodaredevil.solarthing.config.databases.IndividualSettings)

Aggregations

StoredPacketGroup (me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup)5 SolarThingDatabaseException (me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException)4 ArrayList (java.util.ArrayList)3 VersionedPacket (me.retrodaredevil.solarthing.database.VersionedPacket)3 Instant (java.time.Instant)2 DeleteAlterPacket (me.retrodaredevil.solarthing.commands.packets.open.DeleteAlterPacket)2 RequestFlagPacket (me.retrodaredevil.solarthing.commands.packets.open.RequestFlagPacket)2 SolarThingDatabase (me.retrodaredevil.solarthing.database.SolarThingDatabase)2 UpdateConflictSolarThingDatabaseException (me.retrodaredevil.solarthing.database.exception.UpdateConflictSolarThingDatabaseException)2 PacketCollection (me.retrodaredevil.solarthing.packets.collection.PacketCollection)2 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)1 JsonNode (com.fasterxml.jackson.databind.JsonNode)1 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 Duration (java.time.Duration)1 ZoneId (java.time.ZoneId)1 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 List (java.util.List)1 ExecutorService (java.util.concurrent.ExecutorService)1