forked from hatboysam/JavaSnap
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c76fa5b
Showing
7 changed files
with
590 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Ignore Images | ||
*.jpg | ||
|
||
# Mac | ||
.DS_Store | ||
|
||
# IntelliJ | ||
.idea/ | ||
*.iml | ||
*.iws | ||
|
||
# Maven | ||
log/ | ||
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?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>com.habosa</groupId> | ||
<artifactId>JavaSnap</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.mashape.unirest</groupId> | ||
<artifactId>unirest-java</artifactId> | ||
<version>1.3.3</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>commons-io</groupId> | ||
<artifactId>commons-io</artifactId> | ||
<version>2.4</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package com.habosa.javasnap; | ||
|
||
import javax.crypto.*; | ||
import javax.crypto.spec.SecretKeySpec; | ||
import java.security.InvalidKeyException; | ||
import java.security.Key; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.NoSuchProviderException; | ||
|
||
/** | ||
* Author: samstern | ||
* Date: 12/28/13 | ||
*/ | ||
public class Encryption { | ||
|
||
private static final String KEY_ALG = "AES"; | ||
private static final String AES_KEY = "M02cnQ51Ji97vwT4"; | ||
private static final String CIPHER_MODE = "AES/ECB/PKCS5Padding"; | ||
|
||
public static byte[] encrypt(byte[] data) throws EncryptionException { | ||
|
||
// Get AES-ECB with the right padding | ||
Cipher cipher = null; | ||
try { | ||
cipher = Cipher.getInstance(CIPHER_MODE); | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new EncryptionException(e); | ||
} catch (NoSuchPaddingException e) { | ||
throw new EncryptionException(e); | ||
} | ||
|
||
// Set the key | ||
byte[] keyBytes = AES_KEY.getBytes(); | ||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, KEY_ALG); | ||
|
||
// Initialize the Cipher | ||
try { | ||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); | ||
} catch (InvalidKeyException e) { | ||
throw new EncryptionException(e); | ||
} | ||
|
||
// Encrypt the data | ||
try { | ||
byte[] result = cipher.doFinal(data); | ||
return result; | ||
} catch (IllegalBlockSizeException e) { | ||
throw new EncryptionException(e); | ||
} catch (BadPaddingException e) { | ||
throw new EncryptionException(e); | ||
} | ||
} | ||
|
||
public static byte[] decrypt(byte[] data) throws EncryptionException { | ||
|
||
Cipher cipher = null; | ||
try { | ||
cipher = Cipher.getInstance(CIPHER_MODE); | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new EncryptionException(e); | ||
} catch (NoSuchPaddingException e) { | ||
throw new EncryptionException(e); | ||
} | ||
|
||
byte[] keyBytes = AES_KEY.getBytes(); | ||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, KEY_ALG); | ||
|
||
// Only difference from encrypt method | ||
try { | ||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); | ||
} catch (InvalidKeyException e) { | ||
throw new EncryptionException(e); | ||
} | ||
|
||
try { | ||
byte[] result = cipher.doFinal(data); | ||
return result; | ||
} catch (IllegalBlockSizeException e) { | ||
throw new EncryptionException(e); | ||
} catch (BadPaddingException e) { | ||
throw new EncryptionException(e); | ||
} | ||
} | ||
|
||
public static class EncryptionException extends Exception { | ||
|
||
private Exception cause; | ||
|
||
public EncryptionException(Exception e) { | ||
this.cause = e; | ||
} | ||
|
||
@Override | ||
public void printStackTrace() { | ||
cause.printStackTrace(); | ||
this.printStackTrace(); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.habosa.javasnap; | ||
|
||
import org.json.JSONObject; | ||
|
||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.util.Scanner; | ||
|
||
public class Main { | ||
|
||
public static void main(String[] args) throws Exception { | ||
// Get username and password | ||
Scanner scanner = new Scanner(System.in); | ||
System.out.println("Snapchat username: "); | ||
String username = scanner.nextLine(); | ||
System.out.println("Snapchat password: "); | ||
String password = scanner.nextLine(); | ||
|
||
// Test logging in | ||
System.out.println("Logging in..."); | ||
JSONObject loginObj = Snapchat.login(username, password); | ||
String token = loginObj.getString(Snapchat.AUTH_TOKEN_KEY); | ||
|
||
// Try fetching all snaps | ||
System.out.println("Fetching snaps..."); | ||
Snap[] snapObjs = Snapchat.getSnaps(loginObj); | ||
Snap[] downloadable = Snap.filterDownloadable(snapObjs); | ||
for (Snap s : downloadable) { | ||
byte[] snapBytes = Snapchat.getSnap(s, username, token); | ||
// TODO(samstern): Support video | ||
if (s.isImage()) { | ||
System.out.println("Downloading snap from " + s.getSender()); | ||
File snapFile = new File(s.getSender() + "-" + s.getId() + ".jpg"); | ||
FileOutputStream snapOs = new FileOutputStream(snapFile); | ||
snapOs.write(snapBytes); | ||
snapOs.close(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package com.habosa.javasnap; | ||
|
||
import org.json.JSONException; | ||
import org.json.JSONObject; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
|
||
/** | ||
* Author: samstern | ||
* Date: 12/30/13 | ||
*/ | ||
public class Snap { | ||
|
||
public static int TYPE_IMAGE = 0; | ||
public static int TYPE_VIDEO = 1; | ||
public static int TYPE_VIDEO_NOAUDIO = 2; | ||
|
||
public static int NONE = -1; | ||
public static int SENT = 0; | ||
public static int DELIVERED = 1; | ||
public static int VIEWED = 2; | ||
public static int SCREENSHOT = 3; | ||
|
||
private static final String ID_KEY = "id"; | ||
private static final String SENDER_KEY = "sn"; | ||
private static final String RECIPENT_KEY = "rp"; | ||
private static final String TYPE_KEY = "m"; | ||
private static final String STATE_KEY = "st"; | ||
private static final String TIME_KEY = "t"; | ||
|
||
private String id; | ||
private String sender; | ||
private String recipient; | ||
private int type; | ||
private int state; | ||
private int time; | ||
|
||
public Snap(JSONObject snapObject) { | ||
// Check for fields that always exist | ||
try { | ||
this.id = snapObject.getString(ID_KEY); | ||
this.type = snapObject.getInt(TYPE_KEY); | ||
this.state = snapObject.getInt(STATE_KEY); | ||
} catch (JSONException e) { | ||
e.printStackTrace(); | ||
return; | ||
} | ||
|
||
// Check sender or recipient separately | ||
try { | ||
this.sender = snapObject.getString(SENDER_KEY); | ||
} catch (JSONException e) { | ||
// Ignore | ||
} | ||
try { | ||
this.recipient = snapObject.getString(RECIPENT_KEY); | ||
} catch (JSONException e) { | ||
// Ignore | ||
} | ||
|
||
// Check for time separately because it may not exist. | ||
try { | ||
this.time = snapObject.getInt(TIME_KEY); | ||
} catch (JSONException e) { | ||
return; | ||
} | ||
} | ||
|
||
/** | ||
* Take an array of Snaps and return only those that are downloadable. | ||
* | ||
* @param input the array of Snaps to filter. | ||
* @return the snaps that are downloadable (media and unviewed). | ||
*/ | ||
public static Snap[] filterDownloadable(Snap[] input) { | ||
ArrayList<Snap> result = new ArrayList<Snap>(); | ||
for (Snap s : input) { | ||
if (s.isMedia() && s.isIncoming() && !s.isViewed()) { | ||
result.add(s); | ||
} | ||
} | ||
|
||
return result.toArray(new Snap[result.size()]); | ||
} | ||
|
||
/** | ||
* Determine if a Snap has already been viewed. If not, it can be downloaded. | ||
* | ||
* @return true if it has been viewed, false otherwise. | ||
*/ | ||
public boolean isViewed() { | ||
return (state == VIEWED); | ||
} | ||
|
||
/** | ||
* Determine if a Snap is a still image. | ||
* | ||
* @return true if it is an image, false if it is a video or other. | ||
*/ | ||
public boolean isImage() { | ||
return (type == TYPE_IMAGE); | ||
} | ||
|
||
/** | ||
* Determine if a Snap is a video. | ||
* | ||
* @return true if it is a video, false if it is an image or other. | ||
*/ | ||
public boolean isVideo() { | ||
return (type == TYPE_VIDEO || type == TYPE_VIDEO_NOAUDIO); | ||
} | ||
|
||
/** | ||
* Determine if a Snap is a video or image. If not, can't be downloaded and viewed. | ||
* | ||
* @return true if it is a video or an image, false if other. | ||
*/ | ||
public boolean isMedia() { | ||
return (type <= TYPE_VIDEO); | ||
} | ||
|
||
/** | ||
* Determine if a Snap is incoming or outgoing. | ||
* | ||
* @return true if a snap is incoming, false otherwise. | ||
*/ | ||
public boolean isIncoming() { | ||
return (id.endsWith("r")); | ||
} | ||
|
||
public String getId() { | ||
return id; | ||
} | ||
|
||
public String getSender() { | ||
return sender; | ||
} | ||
|
||
public String getRecipient() { | ||
return recipient; | ||
} | ||
|
||
public int getType() { | ||
return type; | ||
} | ||
|
||
public int getState() { | ||
return state; | ||
} | ||
|
||
public int getTime() { | ||
return time; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
String[] attrs = new String[]{ | ||
id, | ||
sender, | ||
recipient, | ||
Integer.toString(type), | ||
Integer.toString(state), | ||
Integer.toString(time) | ||
}; | ||
return Arrays.toString(attrs); | ||
} | ||
} |
Oops, something went wrong.