First commit
This commit is contained in:
		
						commit
						28e192c519
					
				
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| .gradle/ | ||||
| .idea/ | ||||
| build/ | ||||
| *~ | ||||
| *.swp | ||||
| *.iml | ||||
| local.properties | ||||
							
								
								
									
										24
									
								
								build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								build.gradle
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| apply plugin: 'java' | ||||
| apply plugin: 'application' | ||||
| 
 | ||||
| mainClassName = 'cli.Main' | ||||
| 
 | ||||
| repositories { | ||||
|     mavenCentral() | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     compile 'org.whispersystems:textsecure-java:1.3.0' | ||||
|     compile 'com.madgag.spongycastle:prov:1.51.0.0' | ||||
|     compile 'org.json:json:20141113' | ||||
|     compile 'commons-io:commons-io:2.4' | ||||
|     compile 'net.sourceforge.argparse4j:argparse4j:0.5.0' | ||||
| } | ||||
| 
 | ||||
| jar { | ||||
|     baseName = 'textsecure-cli' | ||||
|     version = '0.0.1' | ||||
|     manifest { | ||||
|         attributes 'Main-Class': 'cli.Main' | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #Tue May 05 12:29:30 CEST 2015 | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip | ||||
							
								
								
									
										164
									
								
								gradlew
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										164
									
								
								gradlew
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @ -0,0 +1,164 @@ | ||||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| ############################################################################## | ||||
| ## | ||||
| ##  Gradle start up script for UN*X | ||||
| ## | ||||
| ############################################################################## | ||||
| 
 | ||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| DEFAULT_JVM_OPTS="" | ||||
| 
 | ||||
| APP_NAME="Gradle" | ||||
| APP_BASE_NAME=`basename "$0"` | ||||
| 
 | ||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||
| MAX_FD="maximum" | ||||
| 
 | ||||
| warn ( ) { | ||||
|     echo "$*" | ||||
| } | ||||
| 
 | ||||
| die ( ) { | ||||
|     echo | ||||
|     echo "$*" | ||||
|     echo | ||||
|     exit 1 | ||||
| } | ||||
| 
 | ||||
| # OS specific support (must be 'true' or 'false'). | ||||
| cygwin=false | ||||
| msys=false | ||||
| darwin=false | ||||
| case "`uname`" in | ||||
|   CYGWIN* ) | ||||
|     cygwin=true | ||||
|     ;; | ||||
|   Darwin* ) | ||||
|     darwin=true | ||||
|     ;; | ||||
|   MINGW* ) | ||||
|     msys=true | ||||
|     ;; | ||||
| esac | ||||
| 
 | ||||
| # For Cygwin, ensure paths are in UNIX format before anything is touched. | ||||
| if $cygwin ; then | ||||
|     [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` | ||||
| fi | ||||
| 
 | ||||
| # Attempt to set APP_HOME | ||||
| # Resolve links: $0 may be a link | ||||
| PRG="$0" | ||||
| # Need this for relative symlinks. | ||||
| while [ -h "$PRG" ] ; do | ||||
|     ls=`ls -ld "$PRG"` | ||||
|     link=`expr "$ls" : '.*-> \(.*\)$'` | ||||
|     if expr "$link" : '/.*' > /dev/null; then | ||||
|         PRG="$link" | ||||
|     else | ||||
|         PRG=`dirname "$PRG"`"/$link" | ||||
|     fi | ||||
| done | ||||
| SAVED="`pwd`" | ||||
| cd "`dirname \"$PRG\"`/" >&- | ||||
| APP_HOME="`pwd -P`" | ||||
| cd "$SAVED" >&- | ||||
| 
 | ||||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||||
| 
 | ||||
| # Determine the Java command to use to start the JVM. | ||||
| if [ -n "$JAVA_HOME" ] ; then | ||||
|     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||||
|         # IBM's JDK on AIX uses strange locations for the executables | ||||
|         JAVACMD="$JAVA_HOME/jre/sh/java" | ||||
|     else | ||||
|         JAVACMD="$JAVA_HOME/bin/java" | ||||
|     fi | ||||
|     if [ ! -x "$JAVACMD" ] ; then | ||||
|         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||||
| 
 | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
|     fi | ||||
| else | ||||
|     JAVACMD="java" | ||||
|     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| 
 | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
| fi | ||||
| 
 | ||||
| # Increase the maximum file descriptors if we can. | ||||
| if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | ||||
|     MAX_FD_LIMIT=`ulimit -H -n` | ||||
|     if [ $? -eq 0 ] ; then | ||||
|         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||||
|             MAX_FD="$MAX_FD_LIMIT" | ||||
|         fi | ||||
|         ulimit -n $MAX_FD | ||||
|         if [ $? -ne 0 ] ; then | ||||
|             warn "Could not set maximum file descriptor limit: $MAX_FD" | ||||
|         fi | ||||
|     else | ||||
|         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||||
|     fi | ||||
| fi | ||||
| 
 | ||||
| # For Darwin, add options to specify how the application appears in the dock | ||||
| if $darwin; then | ||||
|     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||||
| fi | ||||
| 
 | ||||
| # For Cygwin, switch paths to Windows format before running java | ||||
| if $cygwin ; then | ||||
|     APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||||
|     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||||
| 
 | ||||
|     # We build the pattern for arguments to be converted via cygpath | ||||
|     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||||
|     SEP="" | ||||
|     for dir in $ROOTDIRSRAW ; do | ||||
|         ROOTDIRS="$ROOTDIRS$SEP$dir" | ||||
|         SEP="|" | ||||
|     done | ||||
|     OURCYGPATTERN="(^($ROOTDIRS))" | ||||
|     # Add a user-defined pattern to the cygpath arguments | ||||
|     if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||||
|         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||||
|     fi | ||||
|     # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||||
|     i=0 | ||||
|     for arg in "$@" ; do | ||||
|         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||||
|         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option | ||||
| 
 | ||||
|         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition | ||||
|             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||||
|         else | ||||
|             eval `echo args$i`="\"$arg\"" | ||||
|         fi | ||||
|         i=$((i+1)) | ||||
|     done | ||||
|     case $i in | ||||
|         (0) set -- ;; | ||||
|         (1) set -- "$args0" ;; | ||||
|         (2) set -- "$args0" "$args1" ;; | ||||
|         (3) set -- "$args0" "$args1" "$args2" ;; | ||||
|         (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||||
|         (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||||
|         (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||||
|         (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||||
|         (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||||
|         (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||||
|     esac | ||||
| fi | ||||
| 
 | ||||
| # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | ||||
| function splitJvmOpts() { | ||||
|     JVM_OPTS=("$@") | ||||
| } | ||||
| eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | ||||
| JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | ||||
| 
 | ||||
| exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" | ||||
							
								
								
									
										90
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| @if "%DEBUG%" == "" @echo off | ||||
| @rem ########################################################################## | ||||
| @rem | ||||
| @rem  Gradle startup script for Windows | ||||
| @rem | ||||
| @rem ########################################################################## | ||||
| 
 | ||||
| @rem Set local scope for the variables with windows NT shell | ||||
| if "%OS%"=="Windows_NT" setlocal | ||||
| 
 | ||||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| set DEFAULT_JVM_OPTS= | ||||
| 
 | ||||
| set DIRNAME=%~dp0 | ||||
| if "%DIRNAME%" == "" set DIRNAME=. | ||||
| set APP_BASE_NAME=%~n0 | ||||
| set APP_HOME=%DIRNAME% | ||||
| 
 | ||||
| @rem Find java.exe | ||||
| if defined JAVA_HOME goto findJavaFromJavaHome | ||||
| 
 | ||||
| set JAVA_EXE=java.exe | ||||
| %JAVA_EXE% -version >NUL 2>&1 | ||||
| if "%ERRORLEVEL%" == "0" goto init | ||||
| 
 | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
| 
 | ||||
| goto fail | ||||
| 
 | ||||
| :findJavaFromJavaHome | ||||
| set JAVA_HOME=%JAVA_HOME:"=% | ||||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||
| 
 | ||||
| if exist "%JAVA_EXE%" goto init | ||||
| 
 | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
| 
 | ||||
| goto fail | ||||
| 
 | ||||
| :init | ||||
| @rem Get command-line arguments, handling Windowz variants | ||||
| 
 | ||||
| if not "%OS%" == "Windows_NT" goto win9xME_args | ||||
| if "%@eval[2+2]" == "4" goto 4NT_args | ||||
| 
 | ||||
| :win9xME_args | ||||
| @rem Slurp the command line arguments. | ||||
| set CMD_LINE_ARGS= | ||||
| set _SKIP=2 | ||||
| 
 | ||||
| :win9xME_args_slurp | ||||
| if "x%~1" == "x" goto execute | ||||
| 
 | ||||
| set CMD_LINE_ARGS=%* | ||||
| goto execute | ||||
| 
 | ||||
| :4NT_args | ||||
| @rem Get arguments from the 4NT Shell from JP Software | ||||
| set CMD_LINE_ARGS=%$ | ||||
| 
 | ||||
| :execute | ||||
| @rem Setup the command line | ||||
| 
 | ||||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||
| 
 | ||||
| @rem Execute Gradle | ||||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||||
| 
 | ||||
| :end | ||||
| @rem End local scope for the variables with windows NT shell | ||||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||||
| 
 | ||||
| :fail | ||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||
| rem the _cmd.exe /c_ return code! | ||||
| if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||
| exit /b 1 | ||||
| 
 | ||||
| :mainEnd | ||||
| if "%OS%"=="Windows_NT" endlocal | ||||
| 
 | ||||
| :omega | ||||
							
								
								
									
										18
									
								
								settings.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								settings.gradle
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * This settings file was auto generated by the Gradle buildInit task | ||||
|  * | ||||
|  * The settings file is used to specify which projects to include in your build. | ||||
|  * In a single project build this file can be empty or even removed. | ||||
|  * | ||||
|  * Detailed information about configuring a multi-project build in Gradle can be found | ||||
|  * in the user guide at http://gradle.org/docs/2.2.1/userguide/multi_project_builds.html | ||||
|  */ | ||||
| 
 | ||||
| /* | ||||
| // To declare projects as part of a multi-project build use the 'include' method | ||||
| include 'shared' | ||||
| include 'api' | ||||
| include 'services:webservice' | ||||
| */ | ||||
| 
 | ||||
| rootProject.name = 'textsecure-cli' | ||||
							
								
								
									
										2135
									
								
								src/main/java/cli/Base64.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2135
									
								
								src/main/java/cli/Base64.java
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										135
									
								
								src/main/java/cli/JsonAxolotlStore.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/main/java/cli/JsonAxolotlStore.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import org.json.JSONObject; | ||||
| import org.whispersystems.libaxolotl.*; | ||||
| import org.whispersystems.libaxolotl.state.AxolotlStore; | ||||
| import org.whispersystems.libaxolotl.state.PreKeyRecord; | ||||
| import org.whispersystems.libaxolotl.state.SessionRecord; | ||||
| import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class JsonAxolotlStore implements AxolotlStore { | ||||
|     private final JsonPreKeyStore preKeyStore; | ||||
|     private final JsonSessionStore sessionStore; | ||||
|     private final JsonSignedPreKeyStore signedPreKeyStore; | ||||
| 
 | ||||
|     private final JsonIdentityKeyStore identityKeyStore; | ||||
| 
 | ||||
|     public JsonAxolotlStore(JSONObject jsonAxolotl) throws IOException, InvalidKeyException { | ||||
|         this.preKeyStore = new JsonPreKeyStore(jsonAxolotl.getJSONArray("preKeys")); | ||||
|         this.sessionStore = new JsonSessionStore(jsonAxolotl.getJSONArray("sessionStore")); | ||||
|         this.signedPreKeyStore = new JsonSignedPreKeyStore(jsonAxolotl.getJSONArray("signedPreKeyStore")); | ||||
|         this.identityKeyStore = new JsonIdentityKeyStore(jsonAxolotl.getJSONObject("identityKeyStore")); | ||||
|     } | ||||
| 
 | ||||
|     public JsonAxolotlStore(IdentityKeyPair identityKeyPair, int registrationId) { | ||||
|         preKeyStore = new JsonPreKeyStore(); | ||||
|         sessionStore = new JsonSessionStore(); | ||||
|         signedPreKeyStore = new JsonSignedPreKeyStore(); | ||||
|         this.identityKeyStore = new JsonIdentityKeyStore(identityKeyPair, registrationId); | ||||
|     } | ||||
| 
 | ||||
|     public JSONObject getJson() { | ||||
|         return new JSONObject().put("preKeys", preKeyStore.getJson()) | ||||
|                 .put("sessionStore", sessionStore.getJson()) | ||||
|                 .put("signedPreKeyStore", signedPreKeyStore.getJson()) | ||||
|                 .put("identityKeyStore", identityKeyStore.getJson()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public IdentityKeyPair getIdentityKeyPair() { | ||||
|         return identityKeyStore.getIdentityKeyPair(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getLocalRegistrationId() { | ||||
|         return identityKeyStore.getLocalRegistrationId(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void saveIdentity(String name, IdentityKey identityKey) { | ||||
|         identityKeyStore.saveIdentity(name, identityKey); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isTrustedIdentity(String name, IdentityKey identityKey) { | ||||
|         return identityKeyStore.isTrustedIdentity(name, identityKey); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException { | ||||
|         return preKeyStore.loadPreKey(preKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void storePreKey(int preKeyId, PreKeyRecord record) { | ||||
|         preKeyStore.storePreKey(preKeyId, record); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean containsPreKey(int preKeyId) { | ||||
|         return preKeyStore.containsPreKey(preKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void removePreKey(int preKeyId) { | ||||
|         preKeyStore.removePreKey(preKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SessionRecord loadSession(AxolotlAddress address) { | ||||
|         return sessionStore.loadSession(address); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<Integer> getSubDeviceSessions(String name) { | ||||
|         return sessionStore.getSubDeviceSessions(name); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void storeSession(AxolotlAddress address, SessionRecord record) { | ||||
|         sessionStore.storeSession(address, record); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean containsSession(AxolotlAddress address) { | ||||
|         return sessionStore.containsSession(address); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void deleteSession(AxolotlAddress address) { | ||||
|         sessionStore.deleteSession(address); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void deleteAllSessions(String name) { | ||||
|         sessionStore.deleteAllSessions(name); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException { | ||||
|         return signedPreKeyStore.loadSignedPreKey(signedPreKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<SignedPreKeyRecord> loadSignedPreKeys() { | ||||
|         return signedPreKeyStore.loadSignedPreKeys(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record) { | ||||
|         signedPreKeyStore.storeSignedPreKey(signedPreKeyId, record); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean containsSignedPreKey(int signedPreKeyId) { | ||||
|         return signedPreKeyStore.containsSignedPreKey(signedPreKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void removeSignedPreKey(int signedPreKeyId) { | ||||
|         signedPreKeyStore.removeSignedPreKey(signedPreKeyId); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										74
									
								
								src/main/java/cli/JsonIdentityKeyStore.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/main/java/cli/JsonIdentityKeyStore.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONObject; | ||||
| import org.whispersystems.libaxolotl.IdentityKey; | ||||
| import org.whispersystems.libaxolotl.IdentityKeyPair; | ||||
| import org.whispersystems.libaxolotl.InvalidKeyException; | ||||
| import org.whispersystems.libaxolotl.state.IdentityKeyStore; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class JsonIdentityKeyStore implements IdentityKeyStore { | ||||
| 
 | ||||
|     private final Map<String, IdentityKey> trustedKeys = new HashMap<>(); | ||||
| 
 | ||||
|     private final IdentityKeyPair identityKeyPair; | ||||
|     private final int localRegistrationId; | ||||
| 
 | ||||
|     public JsonIdentityKeyStore(JSONObject jsonAxolotl) throws IOException, InvalidKeyException { | ||||
|         localRegistrationId = jsonAxolotl.getInt("registrationId"); | ||||
|         identityKeyPair = new IdentityKeyPair(Base64.decode(jsonAxolotl.getString("identityKey"))); | ||||
| 
 | ||||
|         JSONArray list = jsonAxolotl.getJSONArray("trustedKeys"); | ||||
|         for (int i = 0; i < list.length(); i++) { | ||||
|             JSONObject k = list.getJSONObject(i); | ||||
|             try { | ||||
|                 trustedKeys.put(k.getString("name"), new IdentityKey(Base64.decode(k.getString("identityKey")), 0)); | ||||
|             } catch (InvalidKeyException | IOException e) { | ||||
|                 System.out.println("Error while decoding key for: " + k.getString("name")); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public JsonIdentityKeyStore(IdentityKeyPair identityKeyPair, int localRegistrationId) { | ||||
|         this.identityKeyPair = identityKeyPair; | ||||
|         this.localRegistrationId = localRegistrationId; | ||||
|     } | ||||
| 
 | ||||
|     public JSONObject getJson() { | ||||
|         JSONArray list = new JSONArray(); | ||||
|         for (String name : trustedKeys.keySet()) { | ||||
|             list.put(new JSONObject().put("name", name).put("identityKey", Base64.encodeBytes(trustedKeys.get(name).serialize()))); | ||||
|         } | ||||
| 
 | ||||
|         JSONObject result = new JSONObject(); | ||||
|         result.put("registrationId", localRegistrationId); | ||||
|         result.put("identityKey", Base64.encodeBytes(identityKeyPair.serialize())); | ||||
|         result.put("trustedKeys", list); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public IdentityKeyPair getIdentityKeyPair() { | ||||
|         return identityKeyPair; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getLocalRegistrationId() { | ||||
|         return localRegistrationId; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void saveIdentity(String name, IdentityKey identityKey) { | ||||
|         trustedKeys.put(name, identityKey); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isTrustedIdentity(String name, IdentityKey identityKey) { | ||||
|         IdentityKey trusted = trustedKeys.get(name); | ||||
|         return (trusted == null || trusted.equals(identityKey)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										67
									
								
								src/main/java/cli/JsonPreKeyStore.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/main/java/cli/JsonPreKeyStore.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONObject; | ||||
| import org.whispersystems.libaxolotl.InvalidKeyIdException; | ||||
| import org.whispersystems.libaxolotl.state.PreKeyRecord; | ||||
| import org.whispersystems.libaxolotl.state.PreKeyStore; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class JsonPreKeyStore implements PreKeyStore { | ||||
| 
 | ||||
|     private final Map<Integer, byte[]> store = new HashMap<>(); | ||||
| 
 | ||||
|     public JsonPreKeyStore() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public JsonPreKeyStore(JSONArray list) throws IOException { | ||||
|         for (int i = 0; i < list.length(); i++) { | ||||
|             JSONObject k = list.getJSONObject(i); | ||||
|             try { | ||||
|                 store.put(k.getInt("id"), Base64.decode(k.getString("record"))); | ||||
|             } catch (IOException e) { | ||||
|                 System.out.println("Error while decoding prekey for: " + k.getString("name")); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public JSONArray getJson() { | ||||
|         JSONArray result = new JSONArray(); | ||||
|         for (Integer id : store.keySet()) { | ||||
|             result.put(new JSONObject().put("id", id.toString()).put("record", Base64.encodeBytes(store.get(id)))); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException { | ||||
|         try { | ||||
|             if (!store.containsKey(preKeyId)) { | ||||
|                 throw new InvalidKeyIdException("No such prekeyrecord!"); | ||||
|             } | ||||
| 
 | ||||
|             return new PreKeyRecord(store.get(preKeyId)); | ||||
|         } catch (IOException e) { | ||||
|             throw new AssertionError(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void storePreKey(int preKeyId, PreKeyRecord record) { | ||||
|         store.put(preKeyId, record.serialize()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean containsPreKey(int preKeyId) { | ||||
|         return store.containsKey(preKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void removePreKey(int preKeyId) { | ||||
|         store.remove(preKeyId); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										94
									
								
								src/main/java/cli/JsonSessionStore.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/main/java/cli/JsonSessionStore.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONObject; | ||||
| import org.whispersystems.libaxolotl.AxolotlAddress; | ||||
| import org.whispersystems.libaxolotl.state.SessionRecord; | ||||
| import org.whispersystems.libaxolotl.state.SessionStore; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class JsonSessionStore implements SessionStore { | ||||
| 
 | ||||
|     private Map<AxolotlAddress, byte[]> sessions = new HashMap<>(); | ||||
| 
 | ||||
|     public JsonSessionStore() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public JsonSessionStore(JSONArray list) throws IOException { | ||||
|         for (int i = 0; i < list.length(); i++) { | ||||
|             JSONObject k = list.getJSONObject(i); | ||||
|             try { | ||||
|                 sessions.put(new AxolotlAddress(k.getString("name"), k.getInt("deviceId")), Base64.decode(k.getString("record"))); | ||||
|             } catch (IOException e) { | ||||
|                 System.out.println("Error while decoding prekey for: " + k.getString("name")); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public JSONArray getJson() { | ||||
|         JSONArray result = new JSONArray(); | ||||
|         for (AxolotlAddress address : sessions.keySet()) { | ||||
|             result.put(new JSONObject().put("name", address.getName()). | ||||
|                     put("deviceId", address.getDeviceId()). | ||||
|                     put("record", Base64.encodeBytes(sessions.get(address)))); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public synchronized SessionRecord loadSession(AxolotlAddress remoteAddress) { | ||||
|         try { | ||||
|             if (containsSession(remoteAddress)) { | ||||
|                 return new SessionRecord(sessions.get(remoteAddress)); | ||||
|             } else { | ||||
|                 return new SessionRecord(); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             throw new AssertionError(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public synchronized List<Integer> getSubDeviceSessions(String name) { | ||||
|         List<Integer> deviceIds = new LinkedList<>(); | ||||
| 
 | ||||
|         for (AxolotlAddress key : sessions.keySet()) { | ||||
|             if (key.getName().equals(name) && | ||||
|                     key.getDeviceId() != 1) { | ||||
|                 deviceIds.add(key.getDeviceId()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return deviceIds; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public synchronized void storeSession(AxolotlAddress address, SessionRecord record) { | ||||
|         sessions.put(address, record.serialize()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public synchronized boolean containsSession(AxolotlAddress address) { | ||||
|         return sessions.containsKey(address); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public synchronized void deleteSession(AxolotlAddress address) { | ||||
|         sessions.remove(address); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public synchronized void deleteAllSessions(String name) { | ||||
|         for (AxolotlAddress key : sessions.keySet()) { | ||||
|             if (key.getName().equals(name)) { | ||||
|                 sessions.remove(key); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										84
									
								
								src/main/java/cli/JsonSignedPreKeyStore.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/main/java/cli/JsonSignedPreKeyStore.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONObject; | ||||
| import org.whispersystems.libaxolotl.InvalidKeyIdException; | ||||
| import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; | ||||
| import org.whispersystems.libaxolotl.state.SignedPreKeyStore; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class JsonSignedPreKeyStore implements SignedPreKeyStore { | ||||
| 
 | ||||
|     private final Map<Integer, byte[]> store = new HashMap<>(); | ||||
| 
 | ||||
|     public JsonSignedPreKeyStore() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public JsonSignedPreKeyStore(JSONArray list) throws IOException { | ||||
|         for (int i = 0; i < list.length(); i++) { | ||||
|             JSONObject k = list.getJSONObject(i); | ||||
|             try { | ||||
|                 store.put(k.getInt("id"), Base64.decode(k.getString("record"))); | ||||
|             } catch (IOException e) { | ||||
|                 System.out.println("Error while decoding prekey for: " + k.getString("name")); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public JSONArray getJson() { | ||||
|         JSONArray result = new JSONArray(); | ||||
|         for (Integer id : store.keySet()) { | ||||
|             result.put(new JSONObject().put("id", id.toString()).put("record", store.get(id))); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException { | ||||
|         try { | ||||
|             if (!store.containsKey(signedPreKeyId)) { | ||||
|                 throw new InvalidKeyIdException("No such signedprekeyrecord! " + signedPreKeyId); | ||||
|             } | ||||
| 
 | ||||
|             return new SignedPreKeyRecord(store.get(signedPreKeyId)); | ||||
|         } catch (IOException e) { | ||||
|             throw new AssertionError(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<SignedPreKeyRecord> loadSignedPreKeys() { | ||||
|         try { | ||||
|             List<SignedPreKeyRecord> results = new LinkedList<>(); | ||||
| 
 | ||||
|             for (byte[] serialized : store.values()) { | ||||
|                 results.add(new SignedPreKeyRecord(serialized)); | ||||
|             } | ||||
| 
 | ||||
|             return results; | ||||
|         } catch (IOException e) { | ||||
|             throw new AssertionError(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record) { | ||||
|         store.put(signedPreKeyId, record.serialize()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean containsSignedPreKey(int signedPreKeyId) { | ||||
|         return store.containsKey(signedPreKeyId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void removeSignedPreKey(int signedPreKeyId) { | ||||
|         store.remove(signedPreKeyId); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										148
									
								
								src/main/java/cli/Main.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/main/java/cli/Main.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | ||||
| /** | ||||
|  * Copyright (C) 2015 AsamK | ||||
|  * <p> | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * <p> | ||||
|  * 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 General Public License for more details. | ||||
|  * <p> | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package cli; | ||||
| 
 | ||||
| import net.sourceforge.argparse4j.ArgumentParsers; | ||||
| import net.sourceforge.argparse4j.inf.*; | ||||
| import org.apache.commons.io.IOUtils; | ||||
| import org.whispersystems.libaxolotl.InvalidVersionException; | ||||
| import org.whispersystems.textsecure.api.TextSecureMessageSender; | ||||
| import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; | ||||
| import org.whispersystems.textsecure.api.messages.TextSecureMessage; | ||||
| import org.whispersystems.textsecure.api.push.TextSecureAddress; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.security.Security; | ||||
| 
 | ||||
| public class Main { | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         // Workaround for BKS truststore | ||||
|         Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1); | ||||
| 
 | ||||
|         ArgumentParser parser = ArgumentParsers.newArgumentParser("textsecure-cli") | ||||
|                 .defaultHelp(true) | ||||
|                 .description("Commandline interface for TextSecure."); | ||||
|         Subparsers subparsers = parser.addSubparsers() | ||||
|                 .title("subcommands") | ||||
|                 .dest("command") | ||||
|                 .description("valid subcommands") | ||||
|                 .help("additional help"); | ||||
|         Subparser parserRegister = subparsers.addParser("register"); | ||||
|         Subparser parserVerify = subparsers.addParser("verify"); | ||||
|         parserVerify.addArgument("verificationCode") | ||||
|                 .help("The verification code you received via sms."); | ||||
|         Subparser parserSend = subparsers.addParser("send"); | ||||
|         parserSend.addArgument("recipient") | ||||
|                 .help("Specify the recipients' phone number.") | ||||
|                 .nargs("*"); | ||||
|         parserSend.addArgument("-m", "--message") | ||||
|                 .help("Specify the message, if missing standard input is used."); | ||||
|         Subparser parserReceive = subparsers.addParser("receive"); | ||||
|         parser.addArgument("-u", "--username") | ||||
|                 .required(true) | ||||
|                 .help("Specify your phone number, that will be used for verification."); | ||||
|         Namespace ns = null; | ||||
|         try { | ||||
|             ns = parser.parseArgs(args); | ||||
|         } catch (ArgumentParserException e) { | ||||
|             parser.handleError(e); | ||||
|             System.exit(1); | ||||
|         } | ||||
| 
 | ||||
|         String username = ns.getString("username"); | ||||
|         Manager m = new Manager(username); | ||||
|         if (m.userExists()) { | ||||
|             try { | ||||
|                 m.load(); | ||||
|             } catch (Exception e) { | ||||
|                 System.out.println("Loading file error: " + e.getMessage()); | ||||
|                 System.exit(2); | ||||
|             } | ||||
|         } | ||||
|         switch (ns.getString("command")) { | ||||
|             case "register": | ||||
|                 if (!m.userHasKeys()) { | ||||
|                     m.createNewIdentity(); | ||||
|                 } | ||||
|                 try { | ||||
|                     m.register(); | ||||
|                 } catch (IOException e) { | ||||
|                     System.out.println("Request verify error: " + e.getMessage()); | ||||
|                     System.exit(3); | ||||
|                 } | ||||
|                 break; | ||||
|             case "verify": | ||||
|                 if (!m.userHasKeys()) { | ||||
|                     System.out.println("User has no keys, first call register."); | ||||
|                     System.exit(1); | ||||
|                 } | ||||
|                 if (m.isRegistered()) { | ||||
|                     System.out.println("User registration is already verified"); | ||||
|                     System.exit(1); | ||||
|                 } | ||||
|                 try { | ||||
|                     m.verifyAccount(ns.getString("verificationCode")); | ||||
|                 } catch (IOException e) { | ||||
|                     System.out.println("Verify error: " + e.getMessage()); | ||||
|                     System.exit(3); | ||||
|                 } | ||||
|                 break; | ||||
|             case "send": | ||||
|                 if (!m.isRegistered()) { | ||||
|                     System.out.println("User is not registered."); | ||||
|                     System.exit(1); | ||||
|                 } | ||||
|                 TextSecureMessageSender messageSender = m.getMessageSender(); | ||||
|                 String messageText = ns.getString("message"); | ||||
|                 if (messageText == null) { | ||||
|                     try { | ||||
|                         messageText = IOUtils.toString(System.in); | ||||
|                     } catch (IOException e) { | ||||
|                         System.out.println("Failed to read message from stdin: " + e.getMessage()); | ||||
|                         System.exit(1); | ||||
|                     } | ||||
|                 } | ||||
|                 TextSecureMessage message = TextSecureMessage.newBuilder().withBody(messageText).build(); | ||||
|                 for (String recipient : ns.<String>getList("recipient")) { | ||||
|                     try { | ||||
|                         messageSender.sendMessage(new TextSecureAddress(recipient), message); | ||||
|                     } catch (UntrustedIdentityException | IOException e) { | ||||
|                         System.out.println("Send message: " + e.getMessage()); | ||||
|                     } | ||||
|                 } | ||||
|                 break; | ||||
|             case "receive": | ||||
|                 if (!m.isRegistered()) { | ||||
|                     System.out.println("User is not registered."); | ||||
|                     System.exit(1); | ||||
|                 } | ||||
|                 try { | ||||
|                     message = m.receiveMessage(); | ||||
|                     if (message == null) { | ||||
|                         System.exit(0); | ||||
|                     } else { | ||||
|                         System.out.println("Received message: " + message.getBody().get()); | ||||
|                     } | ||||
|                 } catch (IOException | InvalidVersionException e) { | ||||
|                     System.out.println("Receive message: " + e.getMessage()); | ||||
|                 } | ||||
|                 break; | ||||
|         } | ||||
|         m.save(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										181
									
								
								src/main/java/cli/Manager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								src/main/java/cli/Manager.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,181 @@ | ||||
| /** | ||||
|  * Copyright (C) 2015 AsamK | ||||
|  * <p> | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * <p> | ||||
|  * 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 General Public License for more details. | ||||
|  * <p> | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package cli; | ||||
| 
 | ||||
| import org.apache.commons.io.IOUtils; | ||||
| import org.json.JSONObject; | ||||
| import org.whispersystems.libaxolotl.IdentityKeyPair; | ||||
| import org.whispersystems.libaxolotl.InvalidKeyException; | ||||
| import org.whispersystems.libaxolotl.InvalidVersionException; | ||||
| import org.whispersystems.libaxolotl.state.PreKeyRecord; | ||||
| import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; | ||||
| import org.whispersystems.libaxolotl.util.KeyHelper; | ||||
| import org.whispersystems.libaxolotl.util.guava.Optional; | ||||
| import org.whispersystems.textsecure.api.TextSecureAccountManager; | ||||
| import org.whispersystems.textsecure.api.TextSecureMessagePipe; | ||||
| import org.whispersystems.textsecure.api.TextSecureMessageReceiver; | ||||
| import org.whispersystems.textsecure.api.TextSecureMessageSender; | ||||
| import org.whispersystems.textsecure.api.crypto.TextSecureCipher; | ||||
| import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; | ||||
| import org.whispersystems.textsecure.api.messages.TextSecureMessage; | ||||
| import org.whispersystems.textsecure.api.push.TrustStore; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.nio.file.Path; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.TimeoutException; | ||||
| 
 | ||||
| public class Manager { | ||||
|     private final static String URL = "https://textsecure-service.whispersystems.org"; | ||||
|     private final static TrustStore TRUST_STORE = new WhisperTrustStore(); | ||||
| 
 | ||||
|     private final static String settingsPath = System.getProperty("user.home") + "/.config/textsecure"; | ||||
| 
 | ||||
|     private String username; | ||||
|     private String password; | ||||
|     private String signalingKey; | ||||
| 
 | ||||
|     private boolean registered = false; | ||||
| 
 | ||||
|     private JsonAxolotlStore axolotlStore; | ||||
|     TextSecureAccountManager accountManager; | ||||
| 
 | ||||
|     public Manager(String username) { | ||||
|         this.username = username; | ||||
|     } | ||||
| 
 | ||||
|     private String getFileName() { | ||||
|         String path = settingsPath + "/data"; | ||||
|         new File(path).mkdirs(); | ||||
|         return path + "/" + username; | ||||
|     } | ||||
| 
 | ||||
|     public boolean userExists() { | ||||
|         File f = new File(getFileName()); | ||||
|         if (!f.exists() || f.isDirectory()) { | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     public boolean userHasKeys() { | ||||
|         return axolotlStore != null; | ||||
|     } | ||||
| 
 | ||||
|     public void load() throws IOException, InvalidKeyException { | ||||
|         JSONObject in = new JSONObject(IOUtils.toString(new FileInputStream(getFileName()))); | ||||
|         username = in.getString("username"); | ||||
|         password = in.getString("password"); | ||||
|         signalingKey = in.getString("signalingKey"); | ||||
|         axolotlStore = new JsonAxolotlStore(in.getJSONObject("axolotlStore")); | ||||
|         registered = in.getBoolean("registered"); | ||||
|         accountManager = new TextSecureAccountManager(URL, TRUST_STORE, username, password); | ||||
|     } | ||||
| 
 | ||||
|     public void save() { | ||||
|         String out = new JSONObject().put("username", username) | ||||
|                 .put("password", password) | ||||
|                 .put("signalingKey", signalingKey) | ||||
|                 .put("axolotlStore", axolotlStore.getJson()) | ||||
|                 .put("registered", registered).toString(); | ||||
|         try { | ||||
|             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(getFileName())); | ||||
|             writer.write(out); | ||||
|             writer.flush(); | ||||
|             writer.close(); | ||||
|         } catch (Exception e) { | ||||
|             System.out.println("Saving file error: " + e.getMessage()); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void createNewIdentity() { | ||||
|         IdentityKeyPair identityKey = KeyHelper.generateIdentityKeyPair(); | ||||
|         int registrationId = KeyHelper.generateRegistrationId(false); | ||||
|         axolotlStore = new JsonAxolotlStore(identityKey, registrationId); | ||||
|         registered = false; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isRegistered() { | ||||
|         return registered; | ||||
|     } | ||||
| 
 | ||||
|     public void register() throws IOException { | ||||
|         password = Util.getSecret(18); | ||||
| 
 | ||||
|         accountManager = new TextSecureAccountManager(URL, TRUST_STORE, username, password); | ||||
| 
 | ||||
|         accountManager.requestSmsVerificationCode(); | ||||
|         registered = false; | ||||
|     } | ||||
| 
 | ||||
|     public void verifyAccount(String verificationCode) throws IOException { | ||||
|         verificationCode = verificationCode.replace("-", ""); | ||||
|         signalingKey = Util.getSecret(52); | ||||
|         accountManager.verifyAccount(verificationCode, signalingKey, false, axolotlStore.getLocalRegistrationId()); | ||||
| 
 | ||||
|         //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID))); | ||||
|         registered = true; | ||||
|         int start = 0; | ||||
|         List<PreKeyRecord> oneTimePreKeys = KeyHelper.generatePreKeys(start, 100); | ||||
|         PreKeyRecord lastResortKey = KeyHelper.generateLastResortPreKey(); | ||||
|         int signedPreKeyId = 0; | ||||
|         SignedPreKeyRecord signedPreKeyRecord; | ||||
|         try { | ||||
|             signedPreKeyRecord = KeyHelper.generateSignedPreKey(axolotlStore.getIdentityKeyPair(), signedPreKeyId); | ||||
|         } catch (InvalidKeyException e) { | ||||
|             // Should really not happen | ||||
|             System.out.println("invalid key"); | ||||
|             return; | ||||
|         } | ||||
|         accountManager.setPreKeys(axolotlStore.getIdentityKeyPair().getPublicKey(), lastResortKey, signedPreKeyRecord, oneTimePreKeys); | ||||
|     } | ||||
| 
 | ||||
|     public TextSecureMessageSender getMessageSender() { | ||||
|         return new TextSecureMessageSender(URL, TRUST_STORE, username, password, | ||||
|                 axolotlStore, Optional.<TextSecureMessageSender.EventListener>absent()); | ||||
|     } | ||||
| 
 | ||||
|     public TextSecureMessage receiveMessage() throws IOException, InvalidVersionException { | ||||
|         TextSecureMessageReceiver messageReceiver = new TextSecureMessageReceiver(URL, TRUST_STORE, username, password, signalingKey); | ||||
|         TextSecureMessagePipe messagePipe = null; | ||||
| 
 | ||||
|         try { | ||||
|             messagePipe = messageReceiver.createMessagePipe(); | ||||
| 
 | ||||
|             TextSecureEnvelope envelope; | ||||
|             try { | ||||
|                 envelope = messagePipe.read(5, TimeUnit.SECONDS); | ||||
|             } catch (TimeoutException e) { | ||||
|                 return null; | ||||
|             } | ||||
|             TextSecureCipher cipher = new TextSecureCipher(axolotlStore); | ||||
|             TextSecureMessage message = null; | ||||
|             try { | ||||
|                 message = cipher.decrypt(envelope); | ||||
|             } catch (Exception e) { | ||||
|                 // TODO handle all exceptions | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|             return message; | ||||
|         } finally { | ||||
|             if (messagePipe != null) | ||||
|                 messagePipe.shutdown(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										25
									
								
								src/main/java/cli/Util.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/main/java/cli/Util.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.security.SecureRandom; | ||||
| 
 | ||||
| public class Util { | ||||
|     public static String getSecret(int size) { | ||||
|         byte[] secret = getSecretBytes(size); | ||||
|         return Base64.encodeBytes(secret); | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] getSecretBytes(int size) { | ||||
|         byte[] secret = new byte[size]; | ||||
|         getSecureRandom().nextBytes(secret); | ||||
|         return secret; | ||||
|     } | ||||
| 
 | ||||
|     public static SecureRandom getSecureRandom() { | ||||
|         try { | ||||
|             return SecureRandom.getInstance("SHA1PRNG"); | ||||
|         } catch (NoSuchAlgorithmException e) { | ||||
|             throw new AssertionError(e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/main/java/cli/WhisperTrustStore.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/main/java/cli/WhisperTrustStore.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| package cli; | ||||
| 
 | ||||
| import org.whispersystems.textsecure.api.push.TrustStore; | ||||
| 
 | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.InputStream; | ||||
| 
 | ||||
| public class WhisperTrustStore implements TrustStore { | ||||
| 
 | ||||
|     @Override | ||||
|     public InputStream getKeyStoreInputStream() { | ||||
|         return cli.WhisperTrustStore.class.getResourceAsStream("whisper.store"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getKeyStorePassword() { | ||||
|         return "whisper"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/cli/whisper.store
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/cli/whisper.store
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 AsamK
						AsamK