feat: card-cryptmator plugin

This commit is contained in:
2025-05-09 23:11:58 +08:00
parent 6b1f7c41da
commit 33f08e094f
16 changed files with 1380 additions and 1 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea/
target/

22
LICENSE Normal file
View File

@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2021-2024 Ralph Plawetzki
Copyright (c) 2024-2024 Hatter Jiang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,2 +1,58 @@
# card-cryptomator
# tinyencrypt-cryptomator
> This project is fork from https://github.com/purejava/keepassxc-cryptomator , add GnuPG support
[![GitHub Release](https://img.shields.io/github/v/release/jht5945/gnupg-cryptomator)](https://github.com/jht5945/gnupg-cryptomator/releases)
[![License](https://img.shields.io/github/license/jht5945/gnupg-cryptomator.svg)](https://github.com/jht5945/gnupg-cryptomator/blob/master/LICENSE)
Plug-in for Cryptomator to store vault passwords with card-cli encryption.
# Build Project
Requirement:
* JDK 17 or later
* Maven 3.8.4 or later
```shell
mvn package
```
Copy packaged plugin from `target/card-cryptomator-$VERSION.jar` to Cryptomator plugins directory.
> Usage reference [Wiki](https://github.com/purejava/keepassxc-cryptomator/wiki)
# Configuration
Configure file location:
* `/etc/cryptomator/card_config.json`
* `~/.config/cryptomator/card_config.json`
```json
{
}
```
# Documentation
For documentation please take a look at the [Wiki](https://github.com/purejava/keepassxc-cryptomator/wiki).
Plugin location:
| OS | Default Dir |
| ---- | ---- |
| Mac | `~/Library/Application Support/Cryptomator/Plugins` |
| Linux | `~/.local/share/Cryptomator/plugins` |
| Windows | `%homepath%\AppData\Roaming\Cryptomator\Plugins` |
# How it works?
This plugin use card-cli encrypt and decrypt passwords.
# Copyright
Copyright (C) 2021-2024 Ralph Plawetzki<br>
Copyright (C) 2024-2024 Hatter Jiang
The Cryptomator logo is Copyright (C) of https://cryptomator.org/ <br>
The KeePassXC logo is Copyright (C) of https://keepassxc.org/

7
build.json Normal file
View File

@@ -0,0 +1,7 @@
{
"java": "17",
"builder": {
"name": "maven",
"version": "3.8.4"
}
}

275
dependency-reduced-pom.xml Normal file
View File

@@ -0,0 +1,275 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.hatter</groupId>
<artifactId>card-cryptomator</artifactId>
<name>card-cryptomator</name>
<version>1.0.0</version>
<description>Plug-in for Cryptomator to store vault passwords with card-cli encryption.</description>
<url>https://git.hatter.ink/hatter/card-cryptomator</url>
<developers>
<developer>
<name>Ralph Plawetzki</name>
<email>ralph@purejava.org</email>
<organizationUrl>https://github.com/purejava</organizationUrl>
<timezone>+1</timezone>
</developer>
<developer>
<name>Hatter Jiang</name>
<email>jht5945@gmail.com</email>
<organizationUrl>https://github.com/jht5945</organizationUrl>
<timezone>+8</timezone>
</developer>
</developers>
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
</license>
</licenses>
<scm>
<connection>scm:git:git@github.com:jht5945/tinyencrypt-cryptomator.git</connection>
<developerConnection>scm:git:git@github.com:jht5945/tinyencrypt-cryptomator.git</developerConnection>
<url>git@github.com:jht5945/tinyencrypt-cryptomator.git</url>
</scm>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.3.2</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<includeEmptyDirs>false</includeEmptyDirs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<skipIfEmpty>true</skipIfEmpty>
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>4.0.0-M15</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.7.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<failOnError>false</failOnError>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.7.0</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>opentest4j</artifactId>
<groupId>org.opentest4j</groupId>
</exclusion>
<exclusion>
<artifactId>junit-platform-commons</artifactId>
<groupId>org.junit.platform</groupId>
</exclusion>
<exclusion>
<artifactId>apiguardian-api</artifactId>
<groupId>org.apiguardian</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-platform-engine</artifactId>
<groupId>org.junit.platform</groupId>
</exclusion>
<exclusion>
<artifactId>apiguardian-api</artifactId>
<groupId>org.apiguardian</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-jupiter-params</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<properties>
<api.version>1.3.1</api.version>
<slf4j.version>2.0.13</slf4j.version>
<gson.version>2.11.0</gson.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.2</junit.version>
<keepassxc-proxy.version>1.2.5</keepassxc-proxy.version>
</properties>
</project>

BIN
keepassxc-cryptomator.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

258
keepassxc-cryptomator.svg Normal file
View File

@@ -0,0 +1,258 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="47.142086mm"
height="51.849831mm"
viewBox="0 0 47.142086 51.849831"
version="1.1"
id="svg952"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07, custom)"
sodipodi:docname="Zeichnung.svg">
<defs
id="defs946">
<linearGradient
id="SVGID_1_"
gradientUnits="userSpaceOnUse"
x1="50"
y1="-654.86328"
x2="50"
y2="-728.46722"
gradientTransform="matrix(0.09165435,-0.05291667,-0.05291667,-0.09165435,73.377481,82.400217)">
<stop
offset="0"
style="stop-color:#35762e"
id="stop4" />
<stop
offset="1"
style="stop-color:#6daa43"
id="stop6" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.6415902"
inkscape:cx="89.087397"
inkscape:cy="97.983946"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1440"
inkscape:window-height="836"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata949">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-82.262292,-122.24175)">
<g
id="g6"
style="fill:#666666;stroke:#008000;stroke-opacity:1"
transform="matrix(-0.13229167,-0.22913589,0.22913589,-0.13229167,107.97964,157.68609)">
<path
class="st0"
d="m 44.95,24.54 c -8.971761,0.03124 0.868039,0 24.39,0 v 27.11 c 0,14.91 -12.2,27.11 -27.1,27.11 1.08,10.77 3.62,18.33 7.1,23.06 2.18,2.96 4.69,4.66 7.35,5.21 2.86,0.59 6.17,-0.01 9.72,-1.68 6.76,-3.19 13.88,-9.95 20.23,-19.71 2.35,-3.62 7.19,-4.64 10.8,-2.29 3.62,2.35 4.64,7.19 2.3,10.8 -7.98,12.26 -17.37,20.97 -26.65,25.34 -6.6,3.11 -13.24,4.13 -19.51,2.84 C 47.12,121 41.35,117.32 36.74,111.06 31.49,103.92 27.79,93.27 26.52,78.75 11.88,78.44 0,66.37 0,51.65 V 24.54 h 11.27 c 7.299826,-0.04034 -0.01719,0 33.68,0 z"
id="path4"
style="fill:#666666;stroke:#008000;stroke-opacity:1"
sodipodi:nodetypes="ccscccccccccccsccc" />
</g>
<circle
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd;stroke:#515151;stroke-width:0.331459;stroke-linecap:round;stroke-linejoin:round"
cx="27.638317"
cy="181.29776"
r="4.8577499"
id="circle2"
transform="rotate(-30)" />
<path
style="fill:url(#SVGID_1_);stroke-width:0.105833"
d="m 113.27757,139.50771 c 0.0356,0.0405 0.0713,0.0811 0.0977,0.12689 0.20109,0.34829 0.081,0.79646 -0.26729,0.99754 -0.34828,0.20109 -0.79645,0.081 -0.99754,-0.26729 -0.0265,-0.0458 -0.0438,-0.0969 -0.061,-0.14806 0.18047,-0.15308 0.3807,-0.29312 0.58233,-0.40954 0.20552,-0.13087 0.42303,-0.21979 0.64584,-0.29954 z m -1.94768,2.15102 c 0.40746,0.70574 1.17445,1.0817 1.94341,1.01657 l 1.85737,3.21707 1.19994,0.32152 0.32152,-1.19993 -0.43211,-0.64262 0.15107,-0.56383 -0.56382,-0.15108 0.22855,-0.85297 -0.85297,-0.22855 -0.38809,-0.77802 c 0.43171,-0.62809 0.49878,-1.48559 0.0913,-2.19133 -0.0688,-0.11915 -0.14146,-0.22384 -0.23775,-0.32712 1.37191,0.0267 2.63016,0.76673 3.32724,1.95294 1.0795,1.86975 0.44562,4.26434 -1.43329,5.34913 -1.86975,1.0795 -4.26434,0.44562 -5.34913,-1.43329 -0.68792,-1.19151 -0.69967,-2.65119 -0.0277,-3.85795 0.0505,0.12974 0.0956,0.25031 0.16442,0.36946 z m 2.44346,1.29002 0.25663,-0.14817 1.46579,2.53883 -0.25663,0.14816 z"
id="path9" />
<g
id="g6-3"
style="fill:#666666;stroke:#008000;stroke-opacity:1"
transform="matrix(0.13229167,0.22913589,-0.22913589,0.13229167,103.68703,138.64724)">
<path
class="st0"
d="m 14.7,0 h 6.28 c 1.88,0 3.42,1.54 3.42,3.42 V 24.54 H 44.95 V 3.42 C 44.95,1.54 46.49,0 48.37,0 h 6.28 c 1.88,0 3.42,1.54 3.42,3.42 v 21.12 h 11.27 v 27.11 c 0,14.91 -12.2,27.11 -27.1,27.11 1.08,10.77 3.62,18.33 7.1,23.06 2.18,2.96 4.69,4.66 7.35,5.21 2.86,0.59 6.17,-0.01 9.72,-1.68 6.76,-3.19 13.88,-9.95 20.23,-19.71 2.35,-3.62 7.19,-4.64 10.8,-2.29 3.62,2.35 4.64,7.19 2.3,10.8 -7.98,12.26 -17.37,20.97 -26.65,25.34 -6.6,3.11 -13.24,4.13 -19.51,2.84 C 47.12,121 41.35,117.32 36.74,111.06 31.49,103.92 27.79,93.27 26.52,78.75 11.88,78.44 0,66.37 0,51.65 V 24.54 H 11.27 V 3.42 C 11.27,1.54 12.81,0 14.7,0 Z"
id="path4-6"
style="fill:#666666;stroke:#008000;stroke-opacity:1" />
</g>
<path
d="m 94.582125,149.19927 c -1.448673,0.83639 -1.538826,2.52713 -0.846069,3.72701 l 4.496797,-2.59622 c -0.692756,-1.19989 -2.304688,-1.90793 -3.650728,-1.13079 z"
fill="#cfcfcf"
id="path2"
style="stroke-width:0.0098923" />
<path
d="m 94.84526,149.65503 c -1.176843,0.67945 -1.250139,2.05296 -0.687367,3.02771 l 1.946159,-0.84742 1.706964,-1.26171 c -0.562772,-0.97475 -1.872268,-1.54991 -2.965756,-0.91858 z"
fill="#585e62"
id="path4-5"
style="stroke-width:0.0098923" />
<path
d="m 94.274333,157.82422 a 0.19784549,0.19784549 0 0 1 -0.216358,-0.33062 0.42338937,0.42338937 0 1 0 -0.469621,0.0219 0.19784549,0.19784549 0 0 1 -0.204335,0.33855 0.81898146,0.81898146 0 1 1 0.909459,-0.0424 0.21545374,0.21545374 0 0 1 -0.01914,0.0125 z"
fill="#585e62"
id="path6"
style="stroke-width:0.0098923" />
<rect
fill="#cfcfcf"
height="1.426367"
rx="0.48887613"
transform="rotate(-2.91)"
width="1.0355232"
x="85.189171"
y="159.69926"
id="rect8"
style="stroke-width:0.0098923" />
<path
d="m 93.350895,154.4092 0.620433,-0.0315 0.04748,0.93411 a 0.31061742,0.31061742 0 0 1 -0.294448,0.32598 0.31061742,0.31061742 0 0 1 -0.325985,-0.29445 z"
fill="#585e62"
id="path10"
style="stroke-width:0.0098923" />
<circle
cx="4.0454521"
cy="180.33498"
fill="#cfcfcf"
r="0.74241537"
id="circle12"
style="stroke-width:0.0098923"
transform="rotate(-30)" />
<path
d="m 93.649966,153.41325 a 0.74281091,0.74281091 0 0 0 -0.709153,0.57665 0.74251415,0.74251415 0 0 1 1.065394,0.82483 0.74251415,0.74251415 0 0 0 -0.356241,-1.40148 z"
fill="#b1b1b1"
id="path14"
style="stroke-width:0.0098923" />
<path
d="m 102.22884,153.23168 a 0.21852035,0.21852035 0 0 1 -0.0202,0.0102 0.81908036,0.81908036 0 1 1 0.4915,-0.76648 0.19784549,0.19784549 0 1 1 -0.39536,0.008 0.42338937,0.42338937 0 1 0 -0.25385,0.39581 0.19784549,0.19784549 0 0 1 0.17814,0.35268 z"
fill="#585e62"
id="path16"
style="stroke-width:0.0098923" />
<rect
fill="#cfcfcf"
height="1.426367"
rx="0.48887613"
transform="rotate(122.91)"
width="1.0355232"
x="72.147804"
y="-167.79698"
id="rect18"
style="stroke-width:0.0098923" />
<path
d="m 100.61039,151.66275 a 0.31061742,0.31061742 0 0 1 -0.42954,0.092 l -0.785222,-0.50818 0.337532,-0.52154 0.78522,0.50817 a 0.31061742,0.31061742 0 0 1 0.092,0.42954 z"
fill="#585e62"
id="path20"
style="stroke-width:0.0098923" />
<circle
cx="10.603434"
cy="180.33498"
fill="#cfcfcf"
r="0.74241537"
id="circle22"
style="stroke-width:0.0098923"
transform="rotate(-30)" />
<path
d="m 98.720836,150.48558 a 0.74271198,0.74271198 0 0 1 0.853889,-0.32577 0.74251415,0.74251415 0 0 0 0.181968,1.33488 0.74241522,0.74241522 0 0 1 -1.035857,-1.00911 z"
fill="#b1b1b1"
id="path24"
style="stroke-width:0.0098923" />
<path
d="m 96.628898,158.7571 c -0.31415,0.18138 -0.771089,-0.01 -1.1373,-0.47593 -0.196501,-0.25013 -0.341801,-0.5473 -0.409423,-0.83734 -0.07272,-0.31212 -0.04652,-0.58528 0.07309,-0.77005 a 0.51162844,0.51162844 0 0 1 0.174066,-0.1672 l 0.886851,-0.51203 1.2994,2.25063 z"
fill="#585e62"
id="path26"
style="stroke-width:0.0098923" />
<path
d="m 97.508296,158.24938 c -0.182132,0.10516 -0.529929,-0.14924 -0.86547,-0.63287 -0.180051,-0.25963 -0.333661,-0.552 -0.432725,-0.82389 -0.10664,-0.29253 -0.138444,-0.53221 -0.09011,-0.67582 0.01848,-0.0549 0.04822,-0.0945 0.08874,-0.11795 0.04052,-0.0234 0.08991,-0.0291 0.146482,-0.0183 l 0.642568,0.12967 c 0.224583,0.0453 0.516933,0.4326 0.677816,0.77377 0.124006,0.26286 0.172421,0.49649 0.130133,0.62485 l -0.208944,0.62118 c -0.0182,0.0562 -0.0482,0.0961 -0.08848,0.11938 z"
fill="#585e62"
id="path28"
style="stroke-width:0.0098923" />
<path
d="m 96.393592,156.13782 0.64194,0.12957 c 0.144747,0.0295 0.387014,0.31857 0.541652,0.64575 0.102905,0.21782 0.14041,0.39812 0.111521,0.48539 l -0.20875,0.62072 c -0.07816,0.23223 -0.419847,0.0205 -0.76296,-0.47411 -0.34311,-0.49457 -0.557467,-1.08427 -0.479459,-1.31675 0.02589,-0.0768 0.08216,-0.10501 0.156063,-0.0906 z"
fill="#35393b"
id="path30"
style="stroke-width:0.0098923" />
<path
d="m 101.78578,155.77977 c 0.31407,-0.18132 0.37688,-0.67278 0.15648,-1.22289 -0.11837,-0.29524 -0.30307,-0.56966 -0.52045,-0.77324 -0.23394,-0.21904 -0.48361,-0.33293 -0.70342,-0.32173 a 0.51162844,0.51162844 0 0 0 -0.23184,0.0671 l -0.886934,0.51207 1.299404,2.25063 z"
fill="#585e62"
id="path32"
style="stroke-width:0.0098923" />
<path
d="m 100.90638,156.2875 c 0.18214,-0.10516 0.13573,-0.53355 -0.11535,-1.06596 -0.13482,-0.28574 -0.31122,-0.56496 -0.49714,-0.7867 -0.20002,-0.23861 -0.391772,-0.38595 -0.540226,-0.41595 -0.05683,-0.0114 -0.105989,-0.006 -0.146509,0.0179 -0.04052,0.0234 -0.07012,0.0633 -0.08919,0.11775 l -0.208916,0.62126 c -0.07312,0.21721 0.11617,0.66398 0.331195,0.97389 0.165644,0.23882 0.34376,0.39757 0.476066,0.42512 l 0.64235,0.12968 c 0.0579,0.0122 0.10745,0.006 0.14771,-0.017 z"
fill="#585e62"
id="path34"
style="stroke-width:0.0098923" />
<path
d="m 99.63507,154.26636 -0.20875,0.62072 c -0.04709,0.13982 0.08201,0.4942 0.2883,0.79157 0.137183,0.19802 0.274569,0.32065 0.36459,0.33927 l 0.64194,0.12957 c 0.2406,0.0485 0.22756,-0.35332 -0.0292,-0.89775 -0.25675,-0.54443 -0.66027,-1.02492 -0.900608,-1.0736 -0.07955,-0.0155 -0.131817,0.019 -0.156261,0.0902 z"
fill="#35393b"
id="path36"
style="stroke-width:0.0098923" />
<path
d="m 99.35002,151.60246 a 0.82719201,0.82719201 0 0 1 -0.230348,-0.38788 c -0.13651,-0.52807 -0.50953,-0.98264 -0.50953,-0.98264 -1.871225,0.42046 -2.573575,1.48037 -2.573575,1.48037 0,0 -1.268496,0.074 -2.572313,1.47999 0,0 0.205571,0.55114 0.593562,0.9347 a 0.8278845,0.8278845 0 0 1 0.219583,0.39398 c 0.04287,0.17594 0.128265,0.43425 0.29749,0.72834 1.228419,2.13501 4.234325,1.28 4.234325,1.28 0,0 2.249816,-2.16876 1.021344,-4.30385 -0.169651,-0.29385 -0.349786,-0.49723 -0.480542,-0.623 z"
fill="#cfcfcf"
id="path38"
style="stroke-width:0.0098923" />
<path
d="m 98.579909,156.13055 c -0.513012,0.11492 -2.703201,0.49554 -3.622069,-1.10153 -0.146654,-0.25401 -0.217385,-0.47326 -0.250876,-0.61259 a 1.2691788,1.2691788 0 0 0 -0.338435,-0.60418 c -0.164799,-0.16278 -0.292223,-0.36964 -0.375791,-0.52882 0.296192,-0.28787 0.611048,-0.52836 0.938639,-0.71692 0.648772,-0.3732 1.130704,-0.41294 1.135315,-0.41366 l 0.22528,-0.0132 0.113783,-0.18357 c 9.26e-4,-5.3e-4 0.277398,-0.39718 0.925947,-0.77036 0.327635,-0.18849 0.693764,-0.33978 1.091629,-0.45115 0.09546,0.15209 0.210333,0.36643 0.268261,0.59068 a 1.2694755,1.2694755 0 0 0 0.35215,0.59626 c 0.103069,0.0994 0.257036,0.2707 0.403308,0.52504 0.92282,1.60393 -0.508578,3.29881 -0.86713,3.68401 z"
fill="#49b04a"
id="path40"
style="stroke-width:0.0098923" />
<path
d="m 97.442395,153.01658 a 0.56841012,0.56841012 0 1 0 -0.324383,0.82604 l 0.393427,1.32027 0.446243,-0.11086 0.320164,-0.33002 -0.943321,-1.00394 a 0.56841012,0.56841012 0 0 0 0.107871,-0.70149 z"
fill="#35393b"
id="path42"
style="stroke-width:0.0098923" />
<g
fill="#49b04a"
id="g56"
transform="matrix(0.00856696,-0.00494614,0.00494614,0.00856696,89.847252,151.93294)">
<path
d="M 454.94,131.08 A 60.64,60.64 0 0 0 394.3,191.72 H 515.58 A 60.64,60.64 0 0 0 454.94,131.08 Z"
id="path44" />
<path
d="m 642.38,131.08 a 60.64,60.64 0 0 0 -60.64,60.64 H 703 a 60.64,60.64 0 0 0 -60.62,-60.64 z"
id="path46" />
<circle
cx="483.23001"
cy="229.42999"
r="11.52"
id="circle48" />
<circle
cx="528.52002"
cy="229.42999"
r="11.52"
id="circle50" />
<circle
cx="573.79999"
cy="229.42999"
r="11.52"
id="circle52" />
<circle
cx="619.09003"
cy="229.42999"
r="11.52"
id="circle54" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

286
pom.xml Normal file
View File

@@ -0,0 +1,286 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.hatter</groupId>
<artifactId>card-cryptomator</artifactId>
<version>1.0.0</version>
<name>card-cryptomator</name>
<description>Plug-in for Cryptomator to store vault passwords with card-cli encryption.</description>
<url>https://git.hatter.ink/hatter/card-cryptomator</url>
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
</license>
</licenses>
<developers>
<developer>
<name>Ralph Plawetzki</name>
<email>ralph@purejava.org</email>
<timezone>+1</timezone>
<organization/>
<organizationUrl>https://github.com/purejava</organizationUrl>
</developer>
<developer>
<name>Hatter Jiang</name>
<email>jht5945@gmail.com</email>
<timezone>+8</timezone>
<organization/>
<organizationUrl>https://github.com/jht5945</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git@github.com:jht5945/tinyencrypt-cryptomator.git</connection>
<developerConnection>scm:git:git@github.com:jht5945/tinyencrypt-cryptomator.git</developerConnection>
<url>git@github.com:jht5945/tinyencrypt-cryptomator.git</url>
</scm>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- runtime dependencies -->
<api.version>1.3.1</api.version>
<keepassxc-proxy.version>1.2.5</keepassxc-proxy.version>
<gson.version>2.11.0</gson.version>
<slf4j.version>2.0.13</slf4j.version>
<junit.version>5.10.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>integrations-api</artifactId>
<version>${api.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.purejava</groupId>
<artifactId>keepassxc-proxy-access</artifactId>
<version>${keepassxc-proxy.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.3.2</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<includeEmptyDirs>false</includeEmptyDirs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<skipIfEmpty>true</skipIfEmpty>
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>4.0.0-M15</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.7.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<failOnError>false</failOnError>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.7.0</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,80 @@
package me.hatter.integrations.card;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author hatterjiang
*/
public class CardAccessProvider implements KeychainAccessProvider {
private static final Logger LOG = LoggerFactory.getLogger(CardAccessProvider.class);
private CardConfig cardConfig;
public CardAccessProvider() {
try {
cardConfig = Utils.loadCardConfig();
if (!Utils.checkCardCliReady(cardConfig)) {
LOG.error("Check card-cli command failed");
cardConfig = null;
}
} catch (KeychainAccessException e) {
cardConfig = null;
LOG.error("Load card-cli config failed", e);
}
}
@Override
public String displayName() {
return "CardCli";
}
@Override
public boolean isSupported() {
return cardConfig != null;
}
@Override
public boolean isLocked() {
// No lock status
return false;
}
@Override
public void storePassphrase(String vault, CharSequence password) throws KeychainAccessException {
storePassphrase(vault, "Vault", password);
}
@Override
public void storePassphrase(String vault, String name, CharSequence password) throws KeychainAccessException {
LOG.info("Store password for: " + vault + " / " + name);
Utils.storePassword(cardConfig, vault, name, password);
}
@Override
public char[] loadPassphrase(String vault) throws KeychainAccessException {
LOG.info("Load password for: " + vault);
final String password = Utils.loadPassword(cardConfig, vault);
return password.toCharArray();
}
@Override
public void deletePassphrase(String vault) throws KeychainAccessException {
LOG.info("Delete password for: " + vault);
Utils.deletePassword(cardConfig, vault);
}
@Override
public void changePassphrase(String vault, CharSequence password) throws KeychainAccessException {
changePassphrase(vault, "Vault", password);
}
@Override
public void changePassphrase(String vault, String name, CharSequence password) throws KeychainAccessException {
LOG.info("Change password for: " + vault + " / " + name);
Utils.storePassword(cardConfig, vault, name, password);
}
}

View File

@@ -0,0 +1,21 @@
package me.hatter.integrations.card;
/**
* card-cli config
*
* @author hatterjiang
*/
public class CardConfig {
/**
* OPTIONAL, Encrypt key base path, default "~/.config/cryptomator/card_keys/"
*/
private String encryptKeyBasePath;
public String getEncryptKeyBasePath() {
return encryptKeyBasePath;
}
public void setEncryptKeyBasePath(String encryptKeyBasePath) {
this.encryptKeyBasePath = encryptKeyBasePath;
}
}

View File

@@ -0,0 +1,13 @@
package me.hatter.integrations.card;
public class CardHmacDecryptResult {
private String plaintext;
public String getPlaintext() {
return plaintext;
}
public void setPlaintext(String plaintext) {
this.plaintext = plaintext;
}
}

View File

@@ -0,0 +1,13 @@
package me.hatter.integrations.card;
public class CardHmacEncryptResult {
private String ciphertext;
public String getCiphertext() {
return ciphertext;
}
public void setCiphertext(String ciphertext) {
this.ciphertext = ciphertext;
}
}

View File

@@ -0,0 +1,285 @@
package me.hatter.integrations.card;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author hatterjiang
*/
public class Utils {
private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
private static final String USER_HOME = System.getProperty("user.home");
private static final String DEFAULT_CARD_COMMAND = new File(USER_HOME, "bin/card-cli").getAbsolutePath();
private static final File CARD_CONFIG_FILE1 = new File("/etc/cryptomator/card_config.json");
private static final File CARD_CONFIG_FILE2 = new File(USER_HOME, ".config/cryptomator/card_config.json");
private static final File DEFAULT_ENCRYPTION_KEY_BASE_PATH = new File(USER_HOME, ".config/cryptomator/card_keys/");
public static boolean isCheckPassphraseStored() {
final StackTraceElement stack = getCallerStackTrace();
if (stack != null) {
return "isPassphraseStored".equals(stack.getMethodName());
}
return false;
}
public static StackTraceElement getCallerStackTrace() {
// org.cryptomator.common.keychain.KeychainManager :: isPassphraseStored
final StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for (int i = 0; i < stackTraceElements.length; i++) {
final StackTraceElement stack = stackTraceElements[i];
if ("org.cryptomator.common.keychain.KeychainManager".equals(stack.getClassName())) {
return stack;
}
}
return null;
}
public static boolean checkCardCliReady(CardConfig cardConfig) {
if (cardConfig == null) {
return false;
}
try {
final UtilsCommandResult versionResult = runCardCli(cardConfig, null, "-V");
if (versionResult.getExitValue() == 0) {
return true;
}
LOG.warn("Check card-cli not success: " + versionResult);
return false;
} catch (KeychainAccessException e) {
LOG.warn("Check card-cli failed", e);
return false;
}
}
public static CardConfig loadCardConfig() throws KeychainAccessException {
final File configFile = getCardConfigFile();
if (configFile == null) {
return new CardConfig();
}
final String configJson = readFile(configFile);
final CardConfig cardConfig;
try {
cardConfig = new Gson().fromJson(configJson, CardConfig.class);
} catch (Exception e) {
throw new KeychainAccessException("Parse card-cli config file: " + configFile + " failed", e);
}
return cardConfig;
}
public static void deletePassword(CardConfig cardConfig, String vault) {
final File keyFile = getKeyFile(cardConfig, vault);
if (keyFile.exists() && keyFile.isFile()) {
keyFile.delete();
}
}
public static String loadPassword(CardConfig cardConfig, String vault) throws KeychainAccessException {
final File keyFile = getKeyFile(cardConfig, vault);
if (isCheckPassphraseStored()) {
LOG.info("Check passphrase stored: " + vault + ", exists: " + keyFile.exists());
if (keyFile.exists()) {
// this is only for check passphrase stored
return "123456";
}
}
if (!keyFile.isFile()) {
throw new KeychainAccessException("Password key file: " + keyFile + " not found");
}
final String encryptedKey = readFile(keyFile);
final byte[] password = decrypt(cardConfig, encryptedKey);
return new String(password, StandardCharsets.UTF_8);
}
public static void storePassword(CardConfig cardConfig, String vault, String name, CharSequence password) throws KeychainAccessException {
final String encryptedPassword = encrypt(cardConfig, password.toString().getBytes(StandardCharsets.UTF_8), name);
final File keyFile = getKeyFile(cardConfig, vault);
writeFile(keyFile, encryptedPassword);
}
private static File getKeyFile(CardConfig cardConfig, String vault) {
final StringBuilder sb = new StringBuilder(vault.length());
for (char c : vault.toCharArray()) {
if ((c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| (c == '-' || c == '.')) {
sb.append(c);
} else if (c == '_') {
sb.append("__");
} else {
sb.append('_');
final String hex = Integer.toHexString(c);
if (hex.length() % 2 != 0) {
sb.append('0');
}
sb.append(hex);
}
}
return new File(getEncryptKeyBasePath(cardConfig), sb.toString());
}
private static String readFile(File file) throws KeychainAccessException {
final StringBuilder sb = new StringBuilder((int) file.length());
try (final BufferedReader reader = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
for (int b; ((b = reader.read()) != -1); ) {
sb.append((char) b);
}
return sb.toString();
} catch (IOException e) {
throw new KeychainAccessException("Read file: " + file + " failed", e);
}
}
private static void writeFile(File file, String content) throws KeychainAccessException {
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(content.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
throw new KeychainAccessException("Write file: " + file + " failed", e);
}
}
private static byte[] decrypt(CardConfig cardConfig, String input) throws KeychainAccessException {
final UtilsCommandResult decryptResult = runCardCli(
cardConfig,
null,
"hmac-decrypt",
"--ciphertext", input,
"--auto-pbe",
"--json"
);
if (decryptResult.getExitValue() != 0) {
throw new KeychainAccessException("card-cli decrypt failed: " + decryptResult);
}
final String resultString = new String(decryptResult.getStdout(), StandardCharsets.UTF_8);
final CardHmacDecryptResult result = new Gson().fromJson(resultString, CardHmacDecryptResult.class);
return Base64.getDecoder().decode(result.getPlaintext());
}
private static String encrypt(CardConfig cardConfig, byte[] input, String name) throws KeychainAccessException {
final UtilsCommandResult encryptResult = runCardCli(
cardConfig,
null,
"hmac-encrypt",
"--plaintext", Base64.getEncoder().encodeToString(input),
"--with-pbe-encrypt",
"--pbe-iteration", "1000000",
"--json"
);
if (encryptResult.getExitValue() != 0) {
throw new KeychainAccessException("card-cli encrypt failed: " + encryptResult);
}
final String resultString = new String(encryptResult.getStdout(), StandardCharsets.UTF_8);
final CardHmacEncryptResult result = new Gson().fromJson(resultString, CardHmacEncryptResult.class);
return result.getCiphertext();
}
private static UtilsCommandResult runCardCli(CardConfig cardConfig, byte[] input, String... arguments) throws KeychainAccessException {
final List<String> commands = new ArrayList<>();
commands.add(DEFAULT_CARD_COMMAND);
if ((arguments == null) || (arguments.length == 0)) {
throw new KeychainAccessException("card-cli not arguments");
}
commands.addAll(Arrays.asList(arguments));
try {
final ProcessBuilder processBuilder = new ProcessBuilder(commands);
final Process process = processBuilder.start();
// ----- STD IN -----
final AtomicReference<IOException> inThreadException = new AtomicReference<>();
final Thread inThread = new Thread(() -> {
if ((input != null) && (input.length > 0)) {
try (OutputStream processIn = process.getOutputStream()) {
processIn.write(input);
} catch (IOException e) {
inThreadException.set(e);
}
}
});
inThread.setDaemon(true);
inThread.setName("card-cli-stdin");
// ----- STD OUT -----
final AtomicReference<IOException> outThreadException = new AtomicReference<>();
final ByteArrayOutputStream outBaos = new ByteArrayOutputStream();
final Thread outThread = getThread(process.getInputStream(), outBaos, outThreadException, "card-cli-stdout");
// ----- STD ERR -----
final AtomicReference<IOException> errThreadException = new AtomicReference<>();
final ByteArrayOutputStream errBaos = new ByteArrayOutputStream();
final Thread errThread = getThread(process.getErrorStream(), errBaos, errThreadException, "card-cli-stderr");
inThread.start();
outThread.start();
errThread.start();
inThread.join();
if (inThreadException.get() != null) {
throw inThreadException.get();
}
outThread.join();
if (outThreadException.get() != null) {
throw outThreadException.get();
}
errThread.join();
if (errThreadException.get() != null) {
throw errThreadException.get();
}
final int exitValue = process.waitFor();
return new UtilsCommandResult(exitValue, outBaos.toByteArray(), errBaos.toByteArray());
} catch (Exception e) {
throw new KeychainAccessException("Run card-cli command failed: " + commands, e);
}
}
private static Thread getThread(InputStream is, ByteArrayOutputStream outBaos, AtomicReference<IOException> outThreadException, String name) {
final Thread outThread = new Thread(() -> {
int b;
try {
while ((b = is.read()) != -1) {
outBaos.write(b);
}
} catch (IOException e) {
outThreadException.set(e);
}
});
outThread.setDaemon(true);
outThread.setName(name);
return outThread;
}
private static File getEncryptKeyBasePath(CardConfig cardConfig) {
final File encryptKeyBase;
if ((cardConfig != null) && StringUtils.isNoneEmpty(cardConfig.getEncryptKeyBasePath())) {
encryptKeyBase = new File(cardConfig.getEncryptKeyBasePath());
} else {
encryptKeyBase = DEFAULT_ENCRYPTION_KEY_BASE_PATH;
}
if (encryptKeyBase.isDirectory()) {
return encryptKeyBase;
}
LOG.info("Make dirs: " + encryptKeyBase);
encryptKeyBase.mkdirs();
return encryptKeyBase;
}
private static File getCardConfigFile() throws KeychainAccessException {
for (File configFile : Arrays.asList(CARD_CONFIG_FILE1, CARD_CONFIG_FILE2)) {
LOG.info("Check config file: " + configFile + ": " + Arrays.asList(configFile.exists(), configFile.isFile()));
if (configFile.exists() && configFile.isFile()) {
return configFile;
}
}
return null;
}
}

View File

@@ -0,0 +1,40 @@
package me.hatter.integrations.card;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
* @author hatterjiang
*/
public class UtilsCommandResult {
private final int exitValue;
private final byte[] stdout;
private final byte[] stderr;
public UtilsCommandResult(int exitValue, byte[] stdout, byte[] stderr) {
this.exitValue = exitValue;
this.stdout = stdout;
this.stderr = stderr;
}
public int getExitValue() {
return exitValue;
}
public byte[] getStdout() {
return stdout;
}
public byte[] getStderr() {
return stderr;
}
@Override
public String toString() {
return "CommandResult{" +
"exitValue=" + exitValue +
", stdout=" + Arrays.toString(stdout) + " (" + new String(stdout, StandardCharsets.UTF_8) + ")" +
", stderr=" + Arrays.toString(stderr) + " (" + new String(stderr, StandardCharsets.UTF_8) + ")" +
'}';
}
}

View File

@@ -0,0 +1 @@
me.hatter.integrations.card.CardAccessProvider

View File

@@ -0,0 +1,20 @@
package me.hatter.integrations.card;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Unit test for simple KeePassXCAccess.
*/
public class KeePassXCAccessTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}