From bc4912b7b4d83ed61d750117ff889b8d74f7d4e9 Mon Sep 17 00:00:00 2001 From: Mike Piekarski Date: Wed, 12 Sep 2018 16:10:19 -0400 Subject: [PATCH 01/15] Updated to fix json stream bug in latest Pineapple Firmware. Updated README to better reflect how to use library. --- README.md | 12 ++++++++++-- pineapple/api.py | 5 ++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fc6cb45..b893a5a 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Some hints: ##### Instantiate a Pineapple object:
 API_TOKEN = "xxxxxxxxxx..."
-from pineapple.pineapple import Pineapple
-fruit = Pineapple(API_TOKEN)
+from pineapple import *
+fruit = pineapple.Pineapple(API_TOKEN)
 
##### Add a notification:
@@ -27,5 +27,13 @@ fruit.getModule("pineap").enable()
 
 fruit.getModule("pineap").deauth('6e:74:64:69:63:6b', ['73:65:62:6b:69:6e', '6e:65:73:67:69:61'], 5, 1)
 
+##### Get SSID Pool +
+p = fruit.getModule("pineap").getSSIDPool()
+
+Returns a dict. The pool is on the key "ssidPool" separated by newlines. To get a quick list, do the following: +
+ssids = p['ssidPool'].split('\n')
+
*To generate API tokens, use the [API Tokens](https://github.com/735tesla/Pineapple-API-Tokens-Module/) module* diff --git a/pineapple/api.py b/pineapple/api.py index 7264448..df39770 100644 --- a/pineapple/api.py +++ b/pineapple/api.py @@ -19,7 +19,10 @@ def request(self, type, module, action, args = None): payload = json.dumps(requestObject) resp = requests.post(self.url, data=payload, headers=self.headers) try: - return json.loads(resp.text) + # Update for latest firmware: + # The latest firmware puts 6 junk chars in the beginning of the json stream + # Filtering that out. + return json.loads(resp.text[6:]) except ValueError as e: print("Error decoding: %".format(repr(resp.text))) print e From eb6834970be527fb4961d4309df0b7b471d373b4 Mon Sep 17 00:00:00 2001 From: Mike Piekarski Date: Thu, 13 Sep 2018 10:45:42 -0400 Subject: [PATCH 02/15] Rewrote the bulk of recon module for latest firmware. Added comments to methods. Need to rewrite pineapple module next --- pineapple/recon.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pineapple/recon.py b/pineapple/recon.py index 1420ee6..f73c477 100644 --- a/pineapple/recon.py +++ b/pineapple/recon.py @@ -4,6 +4,52 @@ class Recon(Module): def __init__(self, api): super(Recon, self).__init__(api, 'Recon') def getScanStatus(self, scanId, scanType): + """ This method is deprecated but left in for compatibility with older firmware """ return self.request('getScanStatus', {'scan': {'scanID': scanId, 'scanType': scanType}}) def startScan(self, scanType, scanDuration): + """ This method is deprecated but left in for compatibility with older firmware """ return self.request('startScan', {'scanType': scanType, 'scanDuration': scanDuration}) + def startNormalScan(self, scanType, scanDuration): + """ Start a Normal Scan + Scan Type: + 0 - 2.4 Ghz + 1 - 5 Ghz + 2 - Both + """ + def startLiveScan(self, scanType, scanDuration): + """ Start a Live Scan + Scan Type: + 0 - 2.4 Ghz + 1 - 5 Ghz + 2 - Both + """ + return self.request('startNormalScan', { 'scanType': scanType, 'scanDuration': scanDuration}) + def checkPineAPDaemon(self): + """ Errors on return but added to mirror recon api """ + return self.request('checkPineAPDaemon') + def startPineAPDaemon(self): + """ Start Pine AP Daemon """ + return self.request('startPineAPDaemon') + def getScans(self): + """ Return a list of Scans """ + return self.request('getScans') + def downloadResults(self, scanId): + """ Download Scan Results by ID + Basically a limited stub right now, + Pending rewrite of Pineapple module to download data + """ + return self.request('downloadResults', { 'scanId': scanId }) + def removeScan(self, scanId): + """ Delete a scan by ID """ + return self.request('removeScan', { 'scanId': scanId}) + def getCurrentScanID(self): + """ Return ID of Current Scan """ + return self.request('getCurrentScanID') + def stopScan(self): + """ Stop currently running scan + Note: This is not by scan ID but rather just currently running scan + """ + return self.request('stopScan') + def loadResults(self, scanId): + return self.request('loadResults', { 'scanId': scanId }) + From d7b9a80670f7f91e600793724612629468809775 Mon Sep 17 00:00:00 2001 From: Mike Piekarski Date: Thu, 13 Sep 2018 12:36:56 -0400 Subject: [PATCH 03/15] Added download functionality to api. Added an example for it in README. --- README.md | 12 +++++++++++- pineapple/api.py | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b893a5a..880b7d6 100644 --- a/README.md +++ b/README.md @@ -35,5 +35,15 @@ Returns a dict. The pool is on the key "ssidPool" separated by newlines. To get
 ssids = p['ssidPool'].split('\n')
 
- +##### Download Scans +Some support for download files via token was added to api and recon +
+fruit.getModule("recon").downloadResults(1)
+
+Will return a dict with key "download" and a unique download token for the results of Scan ID 1. So knowing that,
+you can call api.download now to get the results
+
+myScan = fruit.api.download(fruit.getModule("recon").downloadResults(1)['download'])
+
+myScan will be the raw file text. In the case of a recon scan, it is json. So you can make it more usable with json.loads(myScan) *To generate API tokens, use the [API Tokens](https://github.com/735tesla/Pineapple-API-Tokens-Module/) module* diff --git a/pineapple/api.py b/pineapple/api.py index df39770..76a943a 100644 --- a/pineapple/api.py +++ b/pineapple/api.py @@ -26,3 +26,14 @@ def request(self, type, module, action, args = None): except ValueError as e: print("Error decoding: %".format(repr(resp.text))) print e + + def download(self, dFile): + """ + Download a file by token. Just returning text instead of json as a just in case. + Easy to handle by just grabbing the response object and hitting it with json.loads + -- This was added to be able to download recon scans but I'm sure someone else might have another use for it + """ + requestObject = {'apiToken': self.apiToken, 'download': dFile } + resp = requests.get(self.url, requestObject) + return resp.text + From fca9bec791f1ad49caa1fb6669c6b04ba70aefb4 Mon Sep 17 00:00:00 2001 From: Mike Piekarski Date: Thu, 13 Sep 2018 12:38:34 -0400 Subject: [PATCH 04/15] Typo on the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 880b7d6..37a5375 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ ssids = p['ssidPool'].split('\n') Some support for download files via token was added to api and recon
 fruit.getModule("recon").downloadResults(1)
-
+
Will return a dict with key "download" and a unique download token for the results of Scan ID 1. So knowing that, you can call api.download now to get the results

From 8193c30c7a9ff38525a285e1a0d0dee32eecf00e Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Fri, 14 Sep 2018 13:03:24 -0400
Subject: [PATCH 05/15] Updated the API to be backwards compatible with older
 firmware

---
 pineapple/api.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/pineapple/api.py b/pineapple/api.py
index 76a943a..1188027 100644
--- a/pineapple/api.py
+++ b/pineapple/api.py
@@ -22,7 +22,11 @@ def request(self, type, module, action, args = None):
 			# Update for latest firmware: 
 			# 		The latest firmware puts 6 junk chars in the beginning of the json stream
 			# 		Filtering that out.
-            return json.loads(resp.text[6:])
+            if resp.text[0:6] == ")]}',\n":
+                return json.loads(resp.text[6:])
+            else:
+                return json.loads(resp.text)
+
         except ValueError as e:
             print("Error decoding: %".format(repr(resp.text)))
             print e

From 7bb889ea5ffc3e05ee8f846d72316a3fb9c8c03a Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 10:01:31 -0400
Subject: [PATCH 06/15] Had Normal and Live Scan Swapped in Recon

---
 pineapple/recon.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pineapple/recon.py b/pineapple/recon.py
index f73c477..8e23068 100644
--- a/pineapple/recon.py
+++ b/pineapple/recon.py
@@ -16,6 +16,7 @@ def startNormalScan(self, scanType, scanDuration):
                 1 - 5 Ghz
                 2 - Both
         """
+        return self.request('startNormalScan', {'scanType': scanType, 'scanDuration': scanDuration})
     def startLiveScan(self, scanType, scanDuration):
         """ Start a Live Scan
             Scan Type:
@@ -23,7 +24,7 @@ def startLiveScan(self, scanType, scanDuration):
                 1 - 5 Ghz
                 2 - Both
         """
-        return self.request('startNormalScan', { 'scanType': scanType, 'scanDuration': scanDuration})
+        return self.request('startLiveScan', { 'scanType': scanType, 'scanDuration': scanDuration})
     def checkPineAPDaemon(self):
         """ Errors on return but added to mirror recon api """
         return self.request('checkPineAPDaemon')

From e985e210c486f540bafe99cb5695fe54d40c100e Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 12:44:17 -0400
Subject: [PATCH 07/15] Added some default to clients. Added missing methods to
 logging with some detail about what they do

---
 pineapple/clients.py |  9 +++++++++
 pineapple/logging.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/pineapple/clients.py b/pineapple/clients.py
index 312e253..e6c3984 100644
--- a/pineapple/clients.py
+++ b/pineapple/clients.py
@@ -3,7 +3,16 @@
 class Clients(Module):
     def __init__(self, api):
         super(Clients, self).__init__(api, 'Clients')
+
     def getClientData(self):
+        """
+            Return List of Clients
+        """
         return self.request('getClientData')
+
     def kickClient(self, mac):
+        """
+            Kick a client by mac address
+        """
         return self.request('kickClient', {'mac': mac})
+
diff --git a/pineapple/logging.py b/pineapple/logging.py
index e43b914..f1b6b65 100644
--- a/pineapple/logging.py
+++ b/pineapple/logging.py
@@ -1,15 +1,59 @@
 from module import Module
 
 class Logging(Module):
+
     def __init__(self, api):
         super(Logging, self).__init__(api, 'Logging')
+
     def getSyslog(self):
+        """
+            Return raw syslog
+        """
         return self.request('getSyslog')
+
     def getDmesg(self):
+        """
+            Return raw dmesg
+        """
         return self.request('getDmesg')
+
     def getReportingLog(self):
+        """
+            Return raw reporting log
+        """
         return self.request('getReportingLog')
+
     def getPineapLog(self):
+        """
+            Return PineAP Log in JSON Format
+        """
         return self.request('getPineapLog')
+
     def clearPineapLog(self):
+        """
+            Clear PineAP Log
+        """
         return self.request('clearPineapLog')
+
+    def getPineapLogLocation(self):
+        """
+            Return the path where PineAP Log is written
+    
+            default: /tmp/
+        """
+        return self.request('getPineapLogLocation')
+
+    def setPineapLogLocation(self, location):
+        """
+            Update the path where PineAP Log is written
+
+            default: /tmp/
+        """
+        return self.request('setPineapLogLocation', { 'location': location })
+    
+    def downloadPineapLog(self):
+        """
+            Return the download token for PineAP Log
+        """
+        return self.request('downloadPineapLog')
+

From fb3947d864d20d3bb5b2219d3e50cba80c0c8325 Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:05:20 -0400
Subject: [PATCH 08/15] Updated filters. Added detail.

---
 pineapple/filters.py  | 66 +++++++++++++++++++++++++++++++++++++++++--
 pineapple/tracking.py | 39 +++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/pineapple/filters.py b/pineapple/filters.py
index 788f062..e76c7d1 100644
--- a/pineapple/filters.py
+++ b/pineapple/filters.py
@@ -3,21 +3,81 @@
 class Filters(Module):
     def __init__(self, api):
         super(Filters, self).__init__(api, 'Filters')
+
+    def getSSIDMode(self):
+        """
+            Return SSID Mode
+                Allow or Deny
+        """
+        return self.request('getSSIDData')
+
+    def getClientMode(self):
+        """
+            Return Client Mode
+                Allow or Deny
+        """
+        return self.request('getClientMode')
+
+    def getSSIDFilters(self):
+        """
+            Return SSID Filters from DB
+        """
+        return self.request('getSSIDFilters')
+
+    def getClientFilters(self):
+        """
+            Return Client Filters from DB
+        """
+        return self.request('getClientFilters')
+
     def getClientData(self):
+        """
+            Return array of mode and clientFilters
+        """
         return self.request('getClientData')
+
     def getSSIDData(self):
+        """
+            Return array of mode and ssidFilters
+        """
         return self.request('getSSIDData')
-    def toggleClientMode(self, allow):
-        mode = 'Allow' if enabled else 'Disallow'
+
+    def toggleClientMode(self, mode):
+        """
+            Toggle Client Mode
+                Allow or Deny are valid values.
+                Case Sensitive
+        """
         return self.request('toggleClientMode', {'mode': mode})
+
     def toggleSSIDMode(self, allow):
-        mode = 'Allow' if enabled else 'Disallow'
+        """
+            Toggle SSID Mode
+                Allow or Deny are valid values
+                Case Sensisitve
+        """
         return self.request('toggleSSIDMode', {'mode': mode})
+
     def addClient(self, mac):
+        """
+            Add Client by Mac to Filters
+        """
         return self.request('addClient', {'mac': mac})
+
     def removeClient(self, mac):
+        """
+            Remove Client by Mac from Filters
+        """
         return self.request('removeClient', {'mac': mac})
+
     def addSSID(self, ssid):
+        """
+            Add SSID to Filters
+        """
         return self.request('addSSID', {'ssid': ssid})
+
     def removeSSID(self, ssid):
+        """
+            Remove SSID from Filters
+        """
         return self.request('removeSSID', {'ssid': ssid})
diff --git a/pineapple/tracking.py b/pineapple/tracking.py
index 9340da7..2c91cd4 100644
--- a/pineapple/tracking.py
+++ b/pineapple/tracking.py
@@ -3,15 +3,54 @@
 class Tracking(Module):
     def __init__(self, api):
         super(Tracking, self).__init__(api, 'Tracking')
+
     def getScript(self):
+        """
+            Return contents of user tracking script.
+
+            Default Script contents:
+
+            #!/bin/bash
+
+            echo $MAC
+            echo $TYPE # 0 PROBE; 1 ASSOCIATION
+            echo $SSID
+        """
         return self.request('getScript')
+
     def setScript(self, script):
+        """
+            Set script content for user tracking
+
+            Default Script contents:
+
+            #!/bin/bash
+            echo $MAC
+            echo $TYPE # 0 PROBE; 1 ASSOCIATION
+            echo $SSID
+        """
         return self.request('saveScript', {'trackingScript': script})
+
     def getTrackingList(self):
+        """
+            Return list of macs being tracked
+        """
         return self.request('getTrackingList')
+
     def addMac(self, mac):
+        """
+            Add mac to Tracking List
+        """
         return self.request('addMac', {'mac': mac})
+
     def removeMac(self, mac):
+        """
+            Remove mac from tracking list
+        """
         return self.request('removeMac', {'mac': mac})
+
     def clearMacs(self):
+        """
+            Clear all macs from Tracking
+        """
         return self.request('clearMacs')

From 52aa06ddd3cac7617e0f7a4ab6f8a7564f0b3dda Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:08:58 -0400
Subject: [PATCH 09/15] some comments and a bug fixed in networking

---
 pineapple/networking.py | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/pineapple/networking.py b/pineapple/networking.py
index 00a3448..bb4d1d5 100644
--- a/pineapple/networking.py
+++ b/pineapple/networking.py
@@ -4,6 +4,9 @@ class Networking(Module):
     def __init__(self, api):
         super(Networking, self).__init__(api, 'Networking')
     def getRoutingTable(self):
+        """
+            Return Routing Table
+        """
         return self.request('getRoutingTable')
     def restartDNS(self):
         return self.request('restartDNS')
@@ -16,6 +19,9 @@ def setHostname(self, hostname):
     def resetWirelessConfig(self):
         return self.request('resetWirelessConfig')
     def getInterfaceList(self):
+        """
+            Return List of Interfaces
+        """
         return self.request('getInterfaceList')
     def saveAPConfig(self, apConfig):
         return self.request('saveAPConfig', {'apConfig': apConfig})
@@ -26,15 +32,21 @@ def getMacData(self):
     def setMac(self, mac):
         return self.request('setMac', {'mac': mac})
     def setRandomMac(self):
+        """
+            Set a random mac
+        """
         return self.request('setRandomMac')
     def resetMac(self):
         return self.request('resetMac')
     def scanForNetworks(self, interface):
         return self.request('scanForNetworks', {'interface': interface})
     def getClientInterfaces(self):
+        """
+            Return list of Client Interfaces
+        """
         return self.request('getClientInterfaces')
     def connectToAP(self, interface, security, password = ''):
-        return self.request('connectToAP', {'interface': interface, security: security, key: password})
+        return self.request('connectToAP', {'interface': interface, 'security': security, 'key': password})
     def checkConnection(self):
         return self.request('checkConnection')
     def disconnect(self, interface):

From f6a504a96bd901593ea7ff96a3049d363b326e9c Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:09:39 -0400
Subject: [PATCH 10/15] Spacing for readability in recon

---
 pineapple/recon.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/pineapple/recon.py b/pineapple/recon.py
index 8e23068..54dbeed 100644
--- a/pineapple/recon.py
+++ b/pineapple/recon.py
@@ -3,12 +3,15 @@
 class Recon(Module):
     def __init__(self, api):
         super(Recon, self).__init__(api, 'Recon')
+
     def getScanStatus(self, scanId, scanType):
         """ This method is deprecated but left in for compatibility with older firmware """
         return self.request('getScanStatus', {'scan': {'scanID': scanId, 'scanType': scanType}})
+
     def startScan(self, scanType, scanDuration):
         """ This method is deprecated but left in for compatibility with older firmware """
         return self.request('startScan', {'scanType': scanType, 'scanDuration': scanDuration})
+
     def startNormalScan(self, scanType, scanDuration):
         """ Start a Normal Scan
             Scan Type: 
@@ -17,6 +20,7 @@ def startNormalScan(self, scanType, scanDuration):
                 2 - Both
         """
         return self.request('startNormalScan', {'scanType': scanType, 'scanDuration': scanDuration})
+
     def startLiveScan(self, scanType, scanDuration):
         """ Start a Live Scan
             Scan Type:
@@ -25,32 +29,40 @@ def startLiveScan(self, scanType, scanDuration):
                 2 - Both
         """
         return self.request('startLiveScan', { 'scanType': scanType, 'scanDuration': scanDuration})
+
     def checkPineAPDaemon(self):
         """ Errors on return but added to mirror recon api """
         return self.request('checkPineAPDaemon')
+
     def startPineAPDaemon(self):
         """ Start Pine AP Daemon """
         return self.request('startPineAPDaemon')
+
     def getScans(self):
         """ Return a list of Scans """
         return self.request('getScans')
+
     def downloadResults(self, scanId):
         """ Download Scan Results by ID 
                 Basically a limited stub right now,
                 Pending rewrite of Pineapple module to download data
         """
         return self.request('downloadResults', { 'scanId': scanId })
+
     def removeScan(self, scanId):
         """ Delete a scan by ID """
         return self.request('removeScan', { 'scanId': scanId})
+
     def getCurrentScanID(self):
         """ Return ID of Current Scan """
         return self.request('getCurrentScanID')
+
     def stopScan(self):
         """ Stop currently running scan 
                 Note: This is not by scan ID but rather just currently running scan
         """
         return self.request('stopScan')
+
     def loadResults(self, scanId):
         return self.request('loadResults', { 'scanId': scanId })
 

From 4040edfc762e5555d56f3ae3d6eb5acfbf7f7075 Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:23:54 -0400
Subject: [PATCH 11/15] Updated some bugs in pineap. Fixed a couple bugs.

---
 pineapple/pineap.py | 49 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/pineapple/pineap.py b/pineapple/pineap.py
index f0e8af0..ed5b68f 100644
--- a/pineapple/pineap.py
+++ b/pineapple/pineap.py
@@ -4,26 +4,73 @@
 class Pineap(Module):
     def __init__(self, api):
         super(Pineap, self).__init__(api, 'PineAP')
+
     def getSSIDPool(self):
+        """
+            Return raw SSID Pool.
+
+            Note: It's just a \n terminated list
+        """
         return self.request('getPool')
+
     def clearPool(self):
+        """
+            Clear the SSID Pool
+        """
         return self.request('clearPool')
+
     def addSSID(self, ssid):
+        """
+            Add SSID to Pool
+        """
         return self.request('addSSID', {'ssid': ssid})
+
     def removeSSID(self, ssid):
+        """
+            Remove SSID from Pool
+        """
         return self.request('removeSSID', {'ssid': ssid})
+
     def setPineAPSettings(self, settings):
+        """
+            Set PineAP Settings.
+            Hand settings as a Python Dictionary
+        """
         self.request('setPineAPSettings', {'settings': json.dumps(settings)})
+
     def getPineAPSettings(self):
+        """
+            Get Current PineAP Settings
+        """
         return self.request('getPineAPSettings')
+
     def deauth(self, sta, clients, multiplier, channel):
+        """
+            Deauth a Client from a Station X times on Y Channel
+        
+            Args in order: Station, Client, Multiplier, Channel
+
+        """
         multiplier = 10 if multiplier > 10 else multiplier
-        return self.request('deauth', {'sta': sta, 'clients': clients, 'multiplier': multiplier, channel: channel})
+        return self.request('deauth', {'sta': sta, 'clients': clients, 'multiplier': multiplier, 'channel': channel})
+
     def enable(self):
+        """
+            Enable PineAP
+        """
         return self.request('enable')
+
     def disable(self):
+        """
+            Disable PineAP
+        """
         return self.request('disable')
+
     def saveSettignsAsDefault(self, config = None):
+        """
+            Hand a config as Python Dictionary.
+            Once it updates, save as default
+        """
         if config:
             resp = self.setPineAPSettings(config)
             if (resp['error']):

From 53ba0d08670e8a90c7636ee1a53e33f5527c5315 Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:26:00 -0400
Subject: [PATCH 12/15] Adding list of methods that need to be in PineAP

---
 pineapple/pineap.py | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/pineapple/pineap.py b/pineapple/pineap.py
index ed5b68f..f27753f 100644
--- a/pineapple/pineap.py
+++ b/pineapple/pineap.py
@@ -5,6 +5,48 @@ class Pineap(Module):
     def __init__(self, api):
         super(Pineap, self).__init__(api, 'PineAP')
 
+        """
+            List of Methods this module needs:
+
+            getPool
+clearPool
+addSSID
+addSSIDs
+removeSSID
+getPoolLocation
+setPoolLocation
+setPineAPSettings
+getPineAPSettings
+setEnterpriseSettings
+getEnterpriseSettings
+detectEnterpriseCertificate
+generateEnterpriseCertificate
+clearEnterpriseCertificate
+clearEnterpriseDB
+getEnterpriseData
+startHandshakeCapture
+stopHandshakeCapture
+getHandshake
+getAllHandshakes
+checkCaptureStatus
+downloadHandshake
+downloadAllHandshakes
+clearAllHandshakes
+deleteHandshake
+deauth
+enable
+disable
+enableAutoStart
+disableAutoStart
+downloadPineAPPool
+loadProbes
+inject
+countSSIDs
+downloadJTRHashes
+downloadHashcatHashes
+
+        """
+
     def getSSIDPool(self):
         """
             Return raw SSID Pool.

From d1bc2b779a7d5e3c2fd5b3e2f6b2f3c590de440e Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:31:07 -0400
Subject: [PATCH 13/15] Updated Advanced method list

---
 pineapple/advanced.py | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/pineapple/advanced.py b/pineapple/advanced.py
index f5afccf..6735141 100644
--- a/pineapple/advanced.py
+++ b/pineapple/advanced.py
@@ -2,6 +2,29 @@
 
 class Advanced(Module):
     def __init__(self, api):
+    """
+        Methods this module should have:
+        
+getResources
+dropCaches
+getUSB
+getFstab
+saveFstab
+getCSS
+saveCSS
+formatSDCard
+formatSDCardStatus
+checkForUpgrade
+downloadUpgrade
+getDownloadStatus
+performUpgrade
+getCurrentVersion
+checkApiToken
+addApiToken
+getApiTokens
+revokeApiToken
+    """
+
         super(Advanced, self).__init__(api, 'Advanced')
     def getResources(self):
         return self.request('getResources')

From af842eebc6a2fb27d61cc5565e578f97fad4e155 Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:38:25 -0400
Subject: [PATCH 14/15] Indentation error on Advanced

---
 pineapple/advanced.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pineapple/advanced.py b/pineapple/advanced.py
index 6735141..9c7efdb 100644
--- a/pineapple/advanced.py
+++ b/pineapple/advanced.py
@@ -2,10 +2,10 @@
 
 class Advanced(Module):
     def __init__(self, api):
-    """
+        """
         Methods this module should have:
         
-getResources
+    getResources
 dropCaches
 getUSB
 getFstab
@@ -23,7 +23,7 @@ def __init__(self, api):
 addApiToken
 getApiTokens
 revokeApiToken
-    """
+        """
 
         super(Advanced, self).__init__(api, 'Advanced')
     def getResources(self):

From f4e07d0f33620450b799677555ebba1712a23d5b Mon Sep 17 00:00:00 2001
From: Mike Piekarski 
Date: Mon, 24 Sep 2018 13:45:46 -0400
Subject: [PATCH 15/15] Added note to README just to convey what the rewrite is
 doing.

---
 README.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/README.md b/README.md
index 37a5375..eaa2ba7 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,9 @@ Some hints:
 - To find out more about the WiFi Pineapple API itself, set `debug = True` when instantiating your `Pineapple()`s and it will log the HTTP requests it makes
 - Read the WiFi Pineapple php source located on your pineapple at `/pineapple/modules/$modulename/api/module.php` as well as the corresponding python files in this project
 
+## Notes
+This is currently undergoing a rewrite and some methods may appear to have duplicate functionality. This is being done to keep backward compatibility. Method names will mirror those shipped with Pineapple Firmware and associated Modules. Planning on adding some additional helpers. This README will be updated over time. Feel free to let me know if you want a specific feature.
+
 ## Examples:
 ##### Instantiate a Pineapple object: