-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[crypt][properties] extract properties crypto logic from maven plugin…
… to let it be reused more easily
- Loading branch information
1 parent
6e82858
commit 5cf0213
Showing
8 changed files
with
232 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
codec-core/src/main/java/io/yupiik/tools/codec/simple/properties/PropertiesCodec.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* Copyright (c) 2020 - 2023 - Yupiik SAS - https://www.yupiik.com | ||
* 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 io.yupiik.tools.codec.simple.properties; | ||
|
||
import io.yupiik.tools.codec.Codec; | ||
|
||
import java.util.Collection; | ||
import java.util.Objects; | ||
import java.util.Properties; | ||
import java.util.stream.Collector; | ||
|
||
import static java.util.function.Function.identity; | ||
import static java.util.stream.Collectors.toMap; | ||
|
||
/** | ||
* Helper to (de)cipher a full properties file. | ||
*/ | ||
public class PropertiesCodec { | ||
private final Codec codec; | ||
|
||
public PropertiesCodec(final Codec codec) { | ||
this.codec = codec; | ||
} | ||
|
||
/** | ||
* Cipher a properties instance. | ||
* | ||
* @param keys keys to cipher (others being ignored). | ||
* @param from the values source. | ||
* @param alreadyCiphered the already ciphered properties if it exists, enables to reduce the diff and only recipher what is clear {@code null} means ignore this. | ||
* @return ciphered properties respecting keys and from parameters. | ||
*/ | ||
public Properties crypt(final Collection<String> keys, final Properties from, final Properties alreadyCiphered) { | ||
final Properties to = new Properties(); | ||
to.putAll((keys == null ? from.stringPropertyNames() : keys).stream().collect(toMap(identity(), e -> { | ||
final var value = from.getProperty(e, ""); | ||
if (!value.isBlank() && codec.isEncrypted(value)) { | ||
return value; | ||
} | ||
|
||
if (alreadyCiphered != null) { | ||
final var existingValue = alreadyCiphered.getProperty(e); | ||
if (existingValue != null && codec.isEncrypted(existingValue) && equals(codec, existingValue, value)) { | ||
return existingValue; | ||
} | ||
} | ||
|
||
return codec.encrypt(value); | ||
}))); | ||
return to; | ||
} | ||
|
||
/** | ||
* Decipher a properties instance. | ||
* | ||
* @param from the data to decipher (values). | ||
* @return the clear properties. | ||
*/ | ||
public Properties decrypt(final Properties from) { | ||
return from.stringPropertyNames().stream().collect(Collector.of( | ||
Properties::new, | ||
(a, e) -> { | ||
final var property = from.getProperty(e, ""); | ||
if (codec.isEncrypted(property)) { | ||
a.setProperty(e, codec.decrypt(property)); | ||
} else { | ||
a.setProperty(e, property); | ||
} | ||
}, | ||
(a, b) -> { | ||
a.putAll(b); | ||
return a; | ||
})); | ||
} | ||
|
||
private boolean equals(final Codec codec, final String existingValue, final String value) { | ||
try { | ||
return Objects.equals(value, codec.decrypt(existingValue)); | ||
} catch (final RuntimeException re) { | ||
return false; | ||
} | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
codec-core/src/main/java/io/yupiik/tools/codec/simple/properties/SortedProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright (c) 2020 - 2023 - Yupiik SAS - https://www.yupiik.com | ||
* 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 io.yupiik.tools.codec.simple.properties; | ||
|
||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.Enumeration; | ||
import java.util.LinkedHashSet; | ||
import java.util.Map; | ||
import java.util.Properties; | ||
import java.util.Set; | ||
|
||
import static java.util.Collections.enumeration; | ||
import static java.util.stream.Collectors.toCollection; | ||
import static java.util.stream.Collectors.toList; | ||
|
||
/** | ||
* Simple helper to sort properties per key. | ||
*/ | ||
public class SortedProperties extends Properties { // sorted...depends jvm version so override most of them | ||
@Override | ||
public Set<String> stringPropertyNames() { | ||
return super.stringPropertyNames().stream().sorted().collect(toCollection(LinkedHashSet::new)); | ||
} | ||
|
||
@Override | ||
public Enumeration<Object> keys() { | ||
return enumeration(Collections.list(super.keys()).stream() | ||
.sorted(Comparator.comparing(Object::toString)) | ||
.collect(toList())); | ||
} | ||
|
||
@Override | ||
public Set<Map.Entry<Object, Object>> entrySet() { | ||
return super.entrySet().stream() | ||
.sorted(Comparator.comparing(a -> a.getKey().toString())) | ||
.collect(toCollection(LinkedHashSet::new)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
codec-core/src/test/java/io/yupiik/tools/codec/simple/properties/PropertiesCodecTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright (c) 2020 - 2023 - Yupiik SAS - https://www.yupiik.com | ||
* 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 io.yupiik.tools.codec.simple.properties; | ||
|
||
import io.yupiik.tools.codec.simple.SimpleCodec; | ||
import io.yupiik.tools.codec.simple.SimpleCodecConfiguration; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.StringReader; | ||
import java.util.Set; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
class PropertiesCodecTest { | ||
@Test | ||
void roundTrip() throws IOException { | ||
final var loaded = new LightProperties(e -> { | ||
throw new IllegalStateException(e); | ||
}); | ||
try (final var b = new BufferedReader(new StringReader("#test\na = b\nc=d"))) { | ||
loaded.load(b, false); | ||
} | ||
final var clear = loaded.toWorkProperties(); | ||
|
||
final var configuration = new SimpleCodecConfiguration(); | ||
configuration.setMasterPassword("foo"); | ||
|
||
final var codec = new PropertiesCodec(new SimpleCodec(configuration)); | ||
final var ciphered = codec.crypt(null, clear, null); | ||
assertEquals(Set.of("a", "c"), ciphered.stringPropertyNames()); | ||
// ensure it is ciphered | ||
ciphered.stringPropertyNames().forEach(k -> { | ||
final var value = ciphered.getProperty(k); | ||
assertTrue(value.length() > 2 && value.startsWith("{") && value.endsWith("}"), () -> k + "=" + ciphered.getProperty(k)); | ||
}); | ||
assertEquals(clear, codec.decrypt(ciphered)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.