├── WPM_Latch ├── lib_mysqludf_sys │ ├── Makefile │ ├── lib_mysqludf_sys.so │ ├── install.sh │ ├── lib_mysqludf_sys.sql │ ├── lib_mysqludf_sys.c │ └── lib_mysqludf_sys.html ├── token_template.rb ├── operations_template.rb ├── remove │ ├── dropTrigger.sql │ └── delete.sh ├── comment_template.rb ├── post_template.rb ├── users_template.rb ├── latch_sdk │ ├── README.md │ ├── Error.rb │ ├── LatchResponse.rb │ ├── Latch.rb │ └── LICENSE.txt ├── install.sh └── proof_template.sql └── README.md /WPM_Latch/lib_mysqludf_sys/Makefile: -------------------------------------------------------------------------------- 1 | LIBDIR=/usr/lib 2 | 3 | install: 4 | gcc -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so 5 | -------------------------------------------------------------------------------- /WPM_Latch/lib_mysqludf_sys/lib_mysqludf_sys.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telefonica/WPM-Wordpress-in-Paranoid-Mode/HEAD/WPM_Latch/lib_mysqludf_sys/lib_mysqludf_sys.so -------------------------------------------------------------------------------- /WPM_Latch/token_template.rb: -------------------------------------------------------------------------------- 1 | require_relative 'latch_sdk/Latch' 2 | #require 'json' 3 | 4 | if ARGV.size != 1 5 | puts "Only 1 parameter: token.rb " 6 | exit 7 | end 8 | 9 | appid="%APPID%" 10 | secret="%SECRET%" 11 | 12 | begin 13 | l = Latch.new(appid,secret) 14 | 15 | response = l.pair(ARGV[0].to_s) 16 | puts "#{response.data['accountId']}" 17 | rescue 18 | exit 1 19 | end 20 | -------------------------------------------------------------------------------- /WPM_Latch/operations_template.rb: -------------------------------------------------------------------------------- 1 | require_relative 'latch_sdk/Latch' 2 | 3 | if ARGV.size != 1 4 | puts "Only 1 parameter: operations.rb " 5 | exit 6 | end 7 | 8 | 9 | appid="%APPID%" 10 | secret="%SECRET%" 11 | 12 | begin 13 | l = Latch.new(appid,secret) 14 | 15 | name = ARGV[0].to_s 16 | response = l.createOperation(appid,name,"DISABLED","DISABLED") 17 | puts "#{response.data['operationId']}" 18 | rescue 19 | exit 1 20 | end 21 | -------------------------------------------------------------------------------- /WPM_Latch/remove/dropTrigger.sql: -------------------------------------------------------------------------------- 1 | /* Triggers Drop */ drop trigger LatchCommentsDeleteWP; drop trigger LatchCommentsUpdateWP; drop trigger LatchCommentsInsertWP; drop trigger LatchPostsDeleteWP; drop trigger LatchPostsUpdateWP; drop trigger 2 | LatchPostsInsertWP; drop trigger LatchUsermetaDeleteWP; drop trigger LatchUsermetaInsertWP; drop trigger LatchUsermetaUpdateWP; drop trigger LatchUsersDeleteWP; drop trigger LatchUsersInsertWP; 3 | drop trigger LatchUsersUpdateWP; 4 | -------------------------------------------------------------------------------- /WPM_Latch/comment_template.rb: -------------------------------------------------------------------------------- 1 | require '%LATCH%/latch_sdk/Latch' 2 | 3 | APPID="%APPID%" 4 | SECRET="%SECRET%" 5 | ACCOUNTID="%ACCOUNTID%" 6 | #Others operations 7 | COMMENT="%COMMENT%" 8 | 9 | begin 10 | l = Latch.new(APPID,SECRET) 11 | #puts l.status(ACCOUNTID).data 12 | res = l.operationStatus(ACCOUNTID,COMMENT).data 13 | state = res["operations"][COMMENT]["status"] 14 | if state == "on" 15 | puts "ok" 16 | else 17 | exit 1 18 | end 19 | rescue 20 | puts "latch" 21 | end 22 | -------------------------------------------------------------------------------- /WPM_Latch/remove/delete.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | INST=$PWD 4 | 5 | echo "delete lib mysqludf_sys.so" 6 | sudo apt-get remove libmysqlclient-dev 7 | sudo rm /usr/lib/mysql/plugin/lib_mysqludf_sys.so 8 | sudo rm /etc/apparmor.d/usr.sbin.mysqld 9 | sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld 10 | 11 | mysql -u root -p wordpress < $INST/dropTrigger.sql 12 | if [ $? -eq 0 ] 13 | then 14 | echo "Success! Triggers removed!" 15 | else 16 | echo "Error!" 17 | exit 18 | fi 19 | -------------------------------------------------------------------------------- /WPM_Latch/post_template.rb: -------------------------------------------------------------------------------- 1 | require '%LATCH%/latch_sdk/Latch' 2 | #require 'net/ssh' 3 | #require 'rubygems' 4 | #require_relative 'Comment_latches' 5 | 6 | APPID="%APPID%" 7 | SECRET="%SECRET%" 8 | ACCOUNTID="%ACCOUNTID%" 9 | #Others operations 10 | POST="%POST%" 11 | 12 | begin 13 | l = Latch.new(APPID,SECRET) 14 | #puts l.status(ACCOUNTID).data 15 | res = l.operationStatus(ACCOUNTID,POST).data 16 | state = res["operations"][POST]["status"] 17 | if state == "on" 18 | puts "ok" 19 | else 20 | exit 1 21 | end 22 | rescue 23 | puts "latch" 24 | end 25 | -------------------------------------------------------------------------------- /WPM_Latch/users_template.rb: -------------------------------------------------------------------------------- 1 | require '%LATCH%/latch_sdk/Latch' 2 | #require 'net/ssh' 3 | #require 'rubygems' 4 | #require_relative 'Comment_latches' 5 | 6 | APPID="%APPID%" 7 | SECRET="%SECRET%" 8 | ACCOUNTID="%ACCOUNTID%" 9 | #Others operations 10 | USERS="%USERS%" 11 | 12 | begin 13 | l = Latch.new(APPID,SECRET) 14 | #puts l.status(ACCOUNTID).data 15 | res = l.operationStatus(ACCOUNTID,USERS).data 16 | state = res["operations"][USERS]["status"] 17 | if state == "on" 18 | puts "ok" 19 | else 20 | exit 1 21 | end 22 | rescue 23 | puts "latch" 24 | end 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Wordpress in Paranoid Mode (WPM) is a tool for Hardening Wordpress. 2 | 3 | Requisites: 4 | 5 | 1. Create an App in https://latch.elevenpaths.com 6 | 2. Get an APP ID and SECRET 7 | 8 | Install: 9 | 10 | Execute ./install.sh 11 | 12 | This steps are automatic through of this script: 13 | 14 | Step 1: Give me a token (Latch) 15 | Step 2: Pairing 16 | Step 3: Copying files and create operations 17 | Step 4: Install bundles (Libraries MySQL) 18 | Step 5: Configure AppArmor 19 | Step 6: Dump Triggers on MySQL 20 | 21 | Uninstall: 22 | 23 | In Directory "remove" execute ./uninstall.sh 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 26 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 27 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 28 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 29 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 30 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 31 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 32 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 | 34 | This software doesn't have a QA Process. This software is a Proof of Concept. 35 | 36 | For more information please visit http://www.elevenpaths.com -------------------------------------------------------------------------------- /WPM_Latch/latch_sdk/README.md: -------------------------------------------------------------------------------- 1 | ### LATCH RUBY SDK ### 2 | 3 | 4 | #### PREREQUISITES #### 5 | 6 | * Ruby 1.9.3 or above. 7 | 8 | * Read API documentation (https://latch.elevenpaths.com/www/developers/doc_api). 9 | 10 | * To get the "Application ID" and "Secret", (fundamental values for integrating Latch in any application), it’s necessary to register a developer account in Latch's website: https://latch.elevenpaths.com. On the upper right side, click on "Developer area". 11 | 12 | 13 | #### USING THE SDK IN RUBY #### 14 | 15 | * Require "Latch". Keep in mind where the SDK is placed inside your folder structure. 16 | ``` 17 | require_relative '/latch/Latch' 18 | ``` 19 | 20 | * Create a Latch object with the "Application ID" and "Secret" previously obtained. 21 | ``` 22 | api = Latch.new(appid, app_secret) 23 | ``` 24 | 25 | * Call to Latch Server. Pairing will return an account id that you should store for future api calls 26 | ``` 27 | pairResponse = api.pair(PAIRING_CODE_HERE) 28 | statusResponse = api.status(ACCOUNT_ID_HERE) 29 | unpairResponse = api.unpair(ACCOUNT_ID_HERE) 30 | ``` 31 | 32 | * After every API call, get Latch response data and errors and handle them. 33 | ``` 34 | responseData = response.data 35 | responseError = response.error 36 | ``` 37 | -------------------------------------------------------------------------------- /WPM_Latch/latch_sdk/Error.rb: -------------------------------------------------------------------------------- 1 | #Latch Ruby SDK - Set of reusable classes to allow developers integrate Latch on their applications. 2 | #Copyright (C) 2013 Eleven Paths 3 | # 4 | #This library is free software; you can redistribute it and/or 5 | #modify it under the terms of the GNU Lesser General Public 6 | #License as published by the Free Software Foundation; either 7 | #version 2.1 of the License, or (at your option) any later version. 8 | # 9 | #This library is distributed in the hope that it will be useful, 10 | #but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | #Lesser General Public License for more details. 13 | # 14 | #You should have received a copy of the GNU Lesser General Public 15 | #License along with this library; if not, write to the Free Software 16 | #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | require 'rubygems' 19 | require 'json' 20 | 21 | class Error 22 | 23 | attr_reader :code 24 | attr_reader :message 25 | 26 | # @param string json a Json representation of an error with "code" and "message" elements 27 | def initialize(json) 28 | if (json.is_a?(String)) 29 | json = JSON.Parse(json) 30 | end 31 | 32 | if(json.has_key?("code") && json.has_key?("message")) 33 | @code = json["code"] 34 | @message = json["message"] 35 | else 36 | puts "Error creating error object from string " + json 37 | end 38 | end 39 | 40 | # JSON representing the Error Object 41 | def to_json 42 | error = {} 43 | error["code"] = @code 44 | error["message"] = @message 45 | error.to_json 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /WPM_Latch/lib_mysqludf_sys/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # lib_mysqludf_sys - a library with miscellaneous (operating) system level functions 3 | # Copyright (C) 2007 Roland Bouman 4 | # Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G. 5 | # web: http://www.mysqludf.org/ 6 | # email: mysqludfs@gmail.com, bernardo.damele@gmail.com 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | echo "Compiling the MySQL UDF" 23 | make 24 | 25 | if test $? -ne 0; then 26 | echo "ERROR: You need libmysqlclient development software installed " 27 | echo "to be able to compile this UDF, on Debian/Ubuntu just run:" 28 | echo "apt-get install libmysqlclient15-dev" 29 | exit 1 30 | else 31 | echo "MySQL UDF compiled successfully" 32 | fi 33 | 34 | echo -e "\nPlease provide your MySQL root password" 35 | 36 | mysql -u root -p mysql < lib_mysqludf_sys.sql 37 | 38 | if test $? -ne 0; then 39 | echo "ERROR: unable to install the UDF" 40 | exit 1 41 | else 42 | echo "MySQL UDF installed successfully" 43 | fi 44 | -------------------------------------------------------------------------------- /WPM_Latch/lib_mysqludf_sys/lib_mysqludf_sys.sql: -------------------------------------------------------------------------------- 1 | /* 2 | lib_mysqludf_sys - a library with miscellaneous (operating) system level functions 3 | Copyright (C) 2007 Roland Bouman 4 | Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G. 5 | web: http://www.mysqludf.org/ 6 | email: roland.bouman@gmail.com, bernardo.damele@gmail.com 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | DROP FUNCTION IF EXISTS lib_mysqludf_sys_info; 24 | DROP FUNCTION IF EXISTS sys_get; 25 | DROP FUNCTION IF EXISTS sys_set; 26 | DROP FUNCTION IF EXISTS sys_exec; 27 | DROP FUNCTION IF EXISTS sys_eval; 28 | 29 | CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so'; 30 | CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so'; 31 | CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so'; 32 | CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so'; 33 | CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so'; 34 | -------------------------------------------------------------------------------- /WPM_Latch/latch_sdk/LatchResponse.rb: -------------------------------------------------------------------------------- 1 | #Latch Ruby SDK - Set of reusable classes to allow developers integrate Latch on their applications. 2 | #Copyright (C) 2013 Eleven Paths 3 | # 4 | #This library is free software; you can redistribute it and/or 5 | #modify it under the terms of the GNU Lesser General Public 6 | #License as published by the Free Software Foundation; either 7 | #version 2.1 of the License, or (at your option) any later version. 8 | # 9 | #This library is distributed in the hope that it will be useful, 10 | #but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | #Lesser General Public License for more details. 13 | # 14 | #You should have received a copy of the GNU Lesser General Public 15 | #License along with this library; if not, write to the Free Software 16 | #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | 19 | require 'rubygems' 20 | require 'json' 21 | require_relative 'Error' 22 | 23 | 24 | # This class models a response from any of the endpoints in the Latch API. 25 | # It consists of a "data" and an "error" elements. Although normally only one of them will be 26 | # present, they are not mutually exclusive, since errors can be non fatal, and therefore a response 27 | # could have valid information in the data field and at the same time inform of an error. 28 | class LatchResponse 29 | 30 | attr_accessor :data 31 | attr_accessor :error 32 | 33 | 34 | # @param jsonString a json string received from one of the methods of the Latch API 35 | def initialize(jsonString) 36 | json = JSON.parse(jsonString) 37 | 38 | if(json != nil) 39 | if (json.has_key?("data")) 40 | @data = json["data"] 41 | end 42 | 43 | if (json.has_key?("error")) 44 | @error = Error.new(json["error"]) 45 | end 46 | end 47 | end 48 | 49 | # Get JSON String that represents the LatchResponse object 50 | def to_json 51 | response = {} 52 | 53 | if (@data != nil) 54 | response["data"] = @data 55 | end 56 | 57 | if (@error != nil) 58 | response["error"] = @error.to_json 59 | end 60 | response.to_json 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /WPM_Latch/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ACCOUNTID="" 4 | APPID="" 5 | SECRET="" 6 | COMMENT="" 7 | POST="" 8 | USERS="" 9 | INST=$PWD 10 | 11 | if [ $# -ne 2 ] 12 | then 13 | echo "Usage: ./install.sh " 14 | exit 15 | fi 16 | 17 | APPID=$1 18 | SECRET=$2 19 | 20 | echo -e "\e[34m" 21 | echo -e " ▄█ █▄ ▄███████▄ ▄▄▄▄███▄▄▄▄ " 22 | echo -e "███ ███ ███ ███ ▄██▀▀▀███▀▀▀██▄ " 23 | echo -e "███ ███ ███ ███ ███ ███ ███ " 24 | echo -e "███ ███ ███ ███ ███ ███ ███ " 25 | echo -e "███ ███ ▀█████████▀ ███ ███ ███ " 26 | echo -e "███ ███ ███ ███ ███ ███ " 27 | echo -e "███ ▄█▄ ███ ███ ███ ███ ███ " 28 | echo -e " ▀███▀███▀ ▄████▀ ▀█ ███ █▀ " 29 | 30 | echo 31 | echo 32 | echo -e "\e[96mWordpress in Paranoid Mode with Latch" 33 | echo -e "Chema Alonso & Pablo González @elevenpaths" 34 | echo -e "\e[39m" 35 | 36 | 37 | echo 38 | echo 39 | echo "Go to Install? ENTER..." 40 | read enter 41 | 42 | cp $INST/token_template.rb $INST/token.rb 43 | sed -i "s|%APPID%|$1|g" $INST/token.rb 44 | sed -i "s|%SECRET%|$2|g" $INST/token.rb 45 | 46 | cp $INST/operations_template.rb $INST/operations.rb 47 | sed -i "s|%APPID%|$1|g" $INST/operations.rb 48 | sed -i "s|%SECRET%|$2|g" $INST/operations.rb 49 | 50 | echo 51 | echo "Step 1: Pairing with Latch" 52 | echo "==========================" 53 | echo 54 | echo -n "Give me token:" 55 | read token 56 | echo 57 | echo "Pairing..." 58 | temp=$(ruby token.rb $token) 59 | if [ $? -eq 0 ] 60 | then 61 | ACCOUNTID=$temp 62 | echo "Account ID: $ACCOUNTID" 63 | else 64 | echo "Error: Account ID Invalid" 65 | exit 66 | fi 67 | 68 | echo 69 | echo "Step 2: Creating Ruby files for Latch operations" 70 | echo "================================================" 71 | echo 72 | echo "Copying comment_template.rb to comment.rb" 73 | cp comment_template.rb comment.rb 74 | sed -i "s/%APPID%/$APPID/g" comment.rb 75 | sed -i "s/%SECRET%/$SECRET/g" comment.rb 76 | sed -i "s/%ACCOUNTID%/$ACCOUNTID/g" comment.rb 77 | sed -i "s|%LATCH%|$INST|g" comment.rb 78 | echo "Copying post_template.rb to post.rb" 79 | cp post_template.rb post.rb 80 | sed -i "s/%APPID%/$APPID/g" post.rb 81 | sed -i "s/%SECRET%/$SECRET/g" post.rb 82 | sed -i "s/%ACCOUNTID%/$ACCOUNTID/g" post.rb 83 | sed -i "s|%LATCH%|$INST|g" post.rb 84 | echo "Copying users_template.rb to users.rb" 85 | cp users_template.rb users.rb 86 | sed -i "s/%APPID%/$APPID/g" users.rb 87 | sed -i "s/%SECRET%/$SECRET/g" users.rb 88 | sed -i "s/%ACCOUNTID%/$ACCOUNTID/g" users.rb 89 | sed -i "s|%LATCH%|$INST|g" users.rb 90 | 91 | echo 92 | echo "Step 3: Create Operations" 93 | echo "=========================" 94 | echo 95 | echo "Creating ReadOnly Operation..." 96 | echo 97 | com=$(ruby operations.rb ReadOnly) 98 | 99 | if [ $? -eq 0 ] 100 | then 101 | COMMENT=$com 102 | echo $COMMENT 103 | sed -i "s/%COMMENT%/$COMMENT/g" comment.rb 104 | else 105 | echo "Error: Not Operation" 106 | exit 107 | fi 108 | 109 | echo 110 | echo 111 | echo "Creating Edition Operation..." 112 | echo 113 | pos=$(ruby operations.rb Edition) 114 | 115 | if [ $? -eq 0 ] 116 | then 117 | POST=$pos 118 | echo $POST 119 | sed -i "s/%POST%/$POST/g" post.rb 120 | else 121 | echo "Error: Not Operation" 122 | exit 123 | fi 124 | 125 | echo 126 | echo 127 | echo "Creating Administration Operation" 128 | echo 129 | user=$(ruby operations.rb Administration) 130 | 131 | if [ $? -eq 0 ] 132 | then 133 | USERS=$user 134 | echo $USERS 135 | sed -i "s/%USERS%/$USERS/g" users.rb 136 | else 137 | echo "Error: Not Operation" 138 | exit 139 | fi 140 | 141 | echo 142 | echo "Step 4: Setup lib mysql udf so" 143 | echo "==============================" 144 | echo 145 | sudo apt-get install libmysqlclient-dev 146 | git clone https://github.com/mysqludf/lib_mysqludf_sys.git 147 | cd lib_mysqludf_sys/ 148 | sudo gcc -fPIC -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o /usr/lib/mysql/plugin/lib_mysqludf_sys.so 149 | mysql -u root -p < lib_mysqludf_sys.sql 150 | 151 | echo 152 | echo "Step 5: AppArmor Configuration" 153 | echo "==============================" 154 | echo 155 | cd /etc/apparmor.d/ 156 | sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ 157 | sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld 158 | echo "Reboot MySQL, if this fail, you need reboot MySQL" 159 | sudo /etc/init.d/mysql restart 160 | if [ $? -ne 0 ] 161 | then 162 | echo "Reboot manually MySQL" 163 | fi 164 | 165 | echo 166 | echo "Step 6: Creating Triggers on MySQL" 167 | echo "==================================" 168 | echo 169 | cp $INST/proof_template.sql $INST/proof.sql 170 | sed -i "s|%PATH%|$INST|g" $INST/proof.sql 171 | mysql -u root -p wordpress < $INST/proof.sql 172 | if [ $? -eq 0 ] 173 | then 174 | echo "Success! Triggers on MySQL" 175 | else 176 | echo "Error: MySQL Triggers" 177 | exit 178 | fi 179 | 180 | -------------------------------------------------------------------------------- /WPM_Latch/proof_template.sql: -------------------------------------------------------------------------------- 1 | DELIMITER ;; 2 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchCommentsInsertWP 3 | BEFORE INSERT ON wordpress.wp_comments 4 | FOR EACH ROW 5 | BEGIN 6 | #DECLARE cmd CHAR(255); 7 | DECLARE result int; 8 | 9 | SET result = sys_exec('ruby %PATH%/comment.rb '); 10 | 11 | IF result NOT IN (0) THEN 12 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 13 | SET MESSAGE_TEXT = 'Latch Cerrado'; 14 | END IF; 15 | 16 | 17 | END */;; 18 | DELIMITER ; 19 | DELIMITER ;; 20 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchCommentsUpdateWP 21 | BEFORE UPDATE ON wordpress.wp_comments 22 | FOR EACH ROW 23 | BEGIN 24 | #DECLARE cmd CHAR(255); 25 | DECLARE result int; 26 | 27 | SET result = sys_exec('ruby %PATH%/comment.rb '); 28 | 29 | IF result NOT IN (0) THEN 30 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 31 | SET MESSAGE_TEXT = 'Latch Cerrado'; 32 | END IF; 33 | 34 | 35 | END */;; 36 | DELIMITER ; 37 | DELIMITER ;; 38 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchCommentsDeleteWP 39 | BEFORE DELETE ON wordpress.wp_comments 40 | FOR EACH ROW 41 | BEGIN 42 | #DECLARE cmd CHAR(255); 43 | DECLARE result int; 44 | 45 | SET result = sys_exec('ruby %PATH%/comment.rb '); 46 | 47 | IF result NOT IN (0) THEN 48 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 49 | SET MESSAGE_TEXT = 'Latch Cerrado'; 50 | END IF; 51 | 52 | 53 | END */;; 54 | DELIMITER ; 55 | DELIMITER ;; 56 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchPostsInsertWP 57 | BEFORE INSERT ON wordpress.wp_posts 58 | FOR EACH ROW 59 | BEGIN 60 | #DECLARE cmd CHAR(255); 61 | DECLARE result int; 62 | DECLARE readonly int; 63 | 64 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 65 | 66 | IF readonly NOT IN (0) THEN 67 | SIGNAL SQLSTATE '45000' 68 | SET MESSAGE_TEXT = 'Latch Cerrado'; 69 | END IF; 70 | 71 | SET result = sys_exec('ruby %PATH%/post.rb '); 72 | 73 | IF result NOT IN (0) THEN 74 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 75 | SET MESSAGE_TEXT = 'Latch Cerrado'; 76 | END IF; 77 | 78 | 79 | END */;; 80 | DELIMITER ; 81 | DELIMITER ;; 82 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchPostsUpdateWP 83 | BEFORE UPDATE ON wordpress.wp_posts 84 | FOR EACH ROW 85 | BEGIN 86 | #DECLARE cmd CHAR(255); 87 | DECLARE result int; 88 | DECLARE readonly int; 89 | 90 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 91 | 92 | IF readonly NOT IN (0) THEN 93 | SIGNAL SQLSTATE '45000' 94 | SET MESSAGE_TEXT = 'Latch Cerrado'; 95 | END IF; 96 | 97 | SET result = sys_exec('ruby %PATH%/post.rb '); 98 | 99 | IF result NOT IN (0) THEN 100 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 101 | SET MESSAGE_TEXT = 'Latch Cerrado'; 102 | END IF; 103 | 104 | 105 | END */;; 106 | DELIMITER ; 107 | DELIMITER ;; 108 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchPostsDeleteWP 109 | BEFORE DELETE ON wordpress.wp_posts 110 | FOR EACH ROW 111 | BEGIN 112 | #DECLARE cmd CHAR(255); 113 | DECLARE result int; 114 | 115 | DECLARE readonly int; 116 | 117 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 118 | 119 | IF readonly NOT IN (0) THEN 120 | SIGNAL SQLSTATE '45000' 121 | SET MESSAGE_TEXT = 'Latch Cerrado'; 122 | END IF; 123 | 124 | SET result = sys_exec('ruby %PATH%/post.rb '); 125 | 126 | IF result NOT IN (0) THEN 127 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 128 | SET MESSAGE_TEXT = 'Latch Cerrado'; 129 | END IF; 130 | 131 | 132 | END */;; 133 | DELIMITER ; 134 | DELIMITER ;; 135 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchUsermetaInsertWP 136 | BEFORE INSERT ON wordpress.wp_usermeta 137 | FOR EACH ROW 138 | BEGIN 139 | #DECLARE cmd CHAR(255); 140 | DECLARE result int; 141 | DECLARE readonly int; 142 | 143 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 144 | 145 | IF readonly NOT IN (0) THEN 146 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 147 | SET MESSAGE_TEXT = 'Latch Cerrado'; 148 | END IF; 149 | 150 | 151 | IF NEW.meta_key <> 'session_tokens' THEN 152 | SET result = sys_exec('ruby %PATH%/users.rb '); 153 | IF result NOT IN (0) THEN 154 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 155 | SET MESSAGE_TEXT = 'Latch Cerrado'; 156 | END IF; 157 | END IF; 158 | 159 | 160 | END */;; 161 | DELIMITER ; 162 | DELIMITER ;; 163 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchUsermetaUpdateWP 164 | BEFORE UPDATE ON wordpress.wp_usermeta 165 | FOR EACH ROW 166 | BEGIN 167 | #DECLARE cmd CHAR(255); 168 | DECLARE readonly int; 169 | DECLARE result int; 170 | 171 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 172 | 173 | IF readonly NOT IN (0) THEN 174 | SIGNAL SQLSTATE '45000' 175 | SET MESSAGE_TEXT = 'Latch Cerrado'; 176 | END IF; 177 | 178 | IF NEW.meta_key <> 'session_tokens' THEN 179 | SET result = sys_exec('ruby %PATH%/users.rb '); 180 | IF result NOT IN (0) THEN 181 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 182 | SET MESSAGE_TEXT = 'Latch Cerrado'; 183 | END IF; 184 | END IF; 185 | 186 | END */;; 187 | DELIMITER ; 188 | DELIMITER ;; 189 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchUsermetaDeleteWP 190 | BEFORE DELETE ON wordpress.wp_usermeta 191 | FOR EACH ROW 192 | BEGIN 193 | #DECLARE cmd CHAR(255); 194 | DECLARE result int; 195 | DECLARE readonly int; 196 | 197 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 198 | 199 | IF readonly NOT IN (0) THEN 200 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 201 | SET MESSAGE_TEXT = 'Latch Cerrado'; 202 | END IF; 203 | 204 | SET result = sys_exec('ruby %PATH%/users.rb '); 205 | 206 | IF result NOT IN (0) THEN 207 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 208 | SET MESSAGE_TEXT = 'Latch Cerrado'; 209 | END IF; 210 | 211 | 212 | END */;; 213 | DELIMITER ; 214 | DELIMITER ;; 215 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchUsersInsertWP 216 | BEFORE INSERT ON wordpress.wp_users 217 | FOR EACH ROW 218 | BEGIN 219 | #DECLARE cmd CHAR(255); 220 | DECLARE result int; 221 | DECLARE readonly int; 222 | 223 | SET readonly = sys_exec('ruby %PATH%/comment.rb'); 224 | SET result = sys_exec('ruby %PATH%/users.rb '); 225 | 226 | IF readonly NOT IN (0) THEN 227 | SIGNAL SQLSTATE '45000' 228 | SET MESSAGE_TEXT = 'Latch Cerrado'; 229 | END IF; 230 | 231 | IF result NOT IN (0) THEN 232 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 233 | SET MESSAGE_TEXT = 'Latch Cerrado'; 234 | END IF; 235 | 236 | 237 | END */;; 238 | DELIMITER ; 239 | DELIMITER ;; 240 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchUsersUpdateWP 241 | BEFORE UPDATE ON wordpress.wp_users 242 | FOR EACH ROW 243 | BEGIN 244 | #DECLARE cmd CHAR(255); 245 | DECLARE result int; 246 | DECLARE readonly int; 247 | 248 | SET result = sys_exec('ruby %PATH%/users.rb '); 249 | SET readonly = sys_exec('ruby %PATH%/comment.rb '); 250 | 251 | IF readonly NOT IN (0) THEN 252 | SIGNAL SQLSTATE '45000' 253 | SET MESSAGE_TEXT = 'Latch Cerrado'; 254 | END IF; 255 | 256 | IF result NOT IN (0) THEN 257 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 258 | SET MESSAGE_TEXT = 'Latch Cerrado'; 259 | END IF; 260 | 261 | 262 | END */;; 263 | DELIMITER ; 264 | DELIMITER ;; 265 | /*!50003 CREATE*/ /*!50017 DEFINER=`root`@`127.0.0.1`*/ /*!50003 TRIGGER LatchUsersDeleteWP 266 | BEFORE DELETE ON wordpress.wp_users 267 | FOR EACH ROW 268 | BEGIN 269 | #DECLARE cmd CHAR(255); 270 | DECLARE result int; 271 | DECLARE readonly int; 272 | 273 | SET readonly = sys_exec('ruby %PATH%/comment.rb '); 274 | 275 | IF readonly NOT IN (0) THEN 276 | SIGNAL SQLSTATE '45000' 277 | SET MESSAGE_TEXT = 'Latch Cerrado'; 278 | END IF; 279 | 280 | SET result = sys_exec('ruby %PATH%/users.rb '); 281 | 282 | IF result NOT IN (0) THEN 283 | SIGNAL SQLSTATE '45000' -- "unhandled user-defined exception" 284 | SET MESSAGE_TEXT = 'Latch Cerrado'; 285 | END IF; 286 | 287 | 288 | END */;; 289 | DELIMITER ; 290 | 291 | -------------------------------------------------------------------------------- /WPM_Latch/lib_mysqludf_sys/lib_mysqludf_sys.c: -------------------------------------------------------------------------------- 1 | /* 2 | lib_mysqludf_sys - a library with miscellaneous (operating) system level functions 3 | Copyright (C) 2007 Roland Bouman 4 | Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G. 5 | web: http://www.mysqludf.org/ 6 | email: mysqludfs@gmail.com, bernardo.damele@gmail.com 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) 23 | #define DLLEXP __declspec(dllexport) 24 | #else 25 | #define DLLEXP 26 | #endif 27 | 28 | #ifdef STANDARD 29 | #include 30 | #include 31 | #include 32 | #ifdef __WIN__ 33 | typedef unsigned __int64 ulonglong; 34 | typedef __int64 longlong; 35 | #else 36 | typedef unsigned long long ulonglong; 37 | typedef long long longlong; 38 | #endif /*__WIN__*/ 39 | #else 40 | #include 41 | #include 42 | #endif 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | 50 | #ifdef HAVE_DLOPEN 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | #define LIBVERSION "lib_mysqludf_sys version 0.0.3" 56 | 57 | #ifdef __WIN__ 58 | #define SETENV(name,value) SetEnvironmentVariable(name,value); 59 | #else 60 | #define SETENV(name,value) setenv(name,value,1); 61 | #endif 62 | 63 | DLLEXP 64 | my_bool lib_mysqludf_sys_info_init( 65 | UDF_INIT *initid 66 | , UDF_ARGS *args 67 | , char *message 68 | ); 69 | 70 | DLLEXP 71 | void lib_mysqludf_sys_info_deinit( 72 | UDF_INIT *initid 73 | ); 74 | 75 | DLLEXP 76 | char* lib_mysqludf_sys_info( 77 | UDF_INIT *initid 78 | , UDF_ARGS *args 79 | , char* result 80 | , unsigned long* length 81 | , char *is_null 82 | , char *error 83 | ); 84 | 85 | /** 86 | * sys_get 87 | * 88 | * Gets the value of the specified environment variable. 89 | */ 90 | DLLEXP 91 | my_bool sys_get_init( 92 | UDF_INIT *initid 93 | , UDF_ARGS *args 94 | , char *message 95 | ); 96 | 97 | DLLEXP 98 | void sys_get_deinit( 99 | UDF_INIT *initid 100 | ); 101 | 102 | DLLEXP 103 | char* sys_get( 104 | UDF_INIT *initid 105 | , UDF_ARGS *args 106 | , char* result 107 | , unsigned long* length 108 | , char *is_null 109 | , char *error 110 | ); 111 | 112 | /** 113 | * sys_set 114 | * 115 | * Sets the value of the environment variables. 116 | * This function accepts a set of name/value pairs 117 | * which are then set as environment variables. 118 | * Use sys_get to retrieve the value of such a variable 119 | */ 120 | DLLEXP 121 | my_bool sys_set_init( 122 | UDF_INIT *initid 123 | , UDF_ARGS *args 124 | , char *message 125 | ); 126 | 127 | DLLEXP 128 | void sys_set_deinit( 129 | UDF_INIT *initid 130 | ); 131 | 132 | DLLEXP 133 | long long sys_set( 134 | UDF_INIT *initid 135 | , UDF_ARGS *args 136 | , char *is_null 137 | , char *error 138 | ); 139 | 140 | /** 141 | * sys_exec 142 | * 143 | * executes the argument commandstring and returns its exit status. 144 | * Beware that this can be a security hazard. 145 | */ 146 | DLLEXP 147 | my_bool sys_exec_init( 148 | UDF_INIT *initid 149 | , UDF_ARGS *args 150 | , char *message 151 | ); 152 | 153 | DLLEXP 154 | void sys_exec_deinit( 155 | UDF_INIT *initid 156 | ); 157 | 158 | DLLEXP 159 | my_ulonglong sys_exec( 160 | UDF_INIT *initid 161 | , UDF_ARGS *args 162 | , char *is_null 163 | , char *error 164 | ); 165 | 166 | /** 167 | * sys_eval 168 | * 169 | * executes the argument commandstring and returns its standard output. 170 | * Beware that this can be a security hazard. 171 | */ 172 | DLLEXP 173 | my_bool sys_eval_init( 174 | UDF_INIT *initid 175 | , UDF_ARGS *args 176 | , char *message 177 | ); 178 | 179 | DLLEXP 180 | void sys_eval_deinit( 181 | UDF_INIT *initid 182 | ); 183 | 184 | DLLEXP 185 | char* sys_eval( 186 | UDF_INIT *initid 187 | , UDF_ARGS *args 188 | , char* result 189 | , unsigned long* length 190 | , char *is_null 191 | , char *error 192 | ); 193 | 194 | 195 | #ifdef __cplusplus 196 | } 197 | #endif 198 | 199 | /** 200 | * lib_mysqludf_sys_info 201 | */ 202 | my_bool lib_mysqludf_sys_info_init( 203 | UDF_INIT *initid 204 | , UDF_ARGS *args 205 | , char *message 206 | ){ 207 | my_bool status; 208 | if(args->arg_count!=0){ 209 | strcpy( 210 | message 211 | , "No arguments allowed (udf: lib_mysqludf_sys_info)" 212 | ); 213 | status = 1; 214 | } else { 215 | status = 0; 216 | } 217 | return status; 218 | } 219 | void lib_mysqludf_sys_info_deinit( 220 | UDF_INIT *initid 221 | ){ 222 | } 223 | char* lib_mysqludf_sys_info( 224 | UDF_INIT *initid 225 | , UDF_ARGS *args 226 | , char* result 227 | , unsigned long* length 228 | , char *is_null 229 | , char *error 230 | ){ 231 | strcpy(result,LIBVERSION); 232 | *length = strlen(LIBVERSION); 233 | return result; 234 | } 235 | 236 | my_bool sys_get_init( 237 | UDF_INIT *initid 238 | , UDF_ARGS *args 239 | , char *message 240 | ){ 241 | if(args->arg_count==1 242 | && args->arg_type[0]==STRING_RESULT){ 243 | initid->maybe_null = 1; 244 | return 0; 245 | } else { 246 | strcpy( 247 | message 248 | , "Expected exactly one string type parameter" 249 | ); 250 | return 1; 251 | } 252 | } 253 | void sys_get_deinit( 254 | UDF_INIT *initid 255 | ){ 256 | } 257 | char* sys_get( 258 | UDF_INIT *initid 259 | , UDF_ARGS *args 260 | , char* result 261 | , unsigned long* length 262 | , char *is_null 263 | , char *error 264 | ){ 265 | char* value = getenv(args->args[0]); 266 | if(value == NULL){ 267 | *is_null = 1; 268 | } else { 269 | *length = strlen(value); 270 | } 271 | return value; 272 | } 273 | 274 | my_bool sys_set_init( 275 | UDF_INIT *initid 276 | , UDF_ARGS *args 277 | , char *message 278 | ){ 279 | if(args->arg_count!=2){ 280 | strcpy( 281 | message 282 | , "Expected exactly two arguments" 283 | ); 284 | return 1; 285 | } 286 | if(args->arg_type[0]!=STRING_RESULT){ 287 | strcpy( 288 | message 289 | , "Expected string type for name parameter" 290 | ); 291 | return 1; 292 | } 293 | args->arg_type[1]=STRING_RESULT; 294 | if((initid->ptr=malloc( 295 | args->lengths[0] 296 | + 1 297 | + args->lengths[1] 298 | + 1 299 | ))==NULL){ 300 | strcpy( 301 | message 302 | , "Could not allocate memory" 303 | ); 304 | return 1; 305 | } 306 | return 0; 307 | } 308 | void sys_set_deinit( 309 | UDF_INIT *initid 310 | ){ 311 | if (initid->ptr!=NULL){ 312 | free(initid->ptr); 313 | } 314 | } 315 | long long sys_set( 316 | UDF_INIT *initid 317 | , UDF_ARGS *args 318 | , char *is_null 319 | , char *error 320 | ){ 321 | char *name = initid->ptr; 322 | char *value = name + args->lengths[0] + 1; 323 | memcpy( 324 | name 325 | , args->args[0] 326 | , args->lengths[0] 327 | ); 328 | *(name + args->lengths[0]) = '\0'; 329 | memcpy( 330 | value 331 | , args->args[1] 332 | , args->lengths[1] 333 | ); 334 | *(value + args->lengths[1]) = '\0'; 335 | return SETENV(name,value); 336 | } 337 | 338 | my_bool sys_exec_init( 339 | UDF_INIT *initid 340 | , UDF_ARGS *args 341 | , char *message 342 | ){ 343 | unsigned int i=0; 344 | if(args->arg_count == 1 345 | && args->arg_type[i]==STRING_RESULT){ 346 | return 0; 347 | } else { 348 | strcpy( 349 | message 350 | , "Expected exactly one string type parameter" 351 | ); 352 | return 1; 353 | } 354 | } 355 | void sys_exec_deinit( 356 | UDF_INIT *initid 357 | ){ 358 | } 359 | my_ulonglong sys_exec( 360 | UDF_INIT *initid 361 | , UDF_ARGS *args 362 | , char *is_null 363 | , char *error 364 | ){ 365 | return system(args->args[0]); 366 | } 367 | 368 | my_bool sys_eval_init( 369 | UDF_INIT *initid 370 | , UDF_ARGS *args 371 | , char *message 372 | ){ 373 | unsigned int i=0; 374 | if(args->arg_count == 1 375 | && args->arg_type[i]==STRING_RESULT){ 376 | return 0; 377 | } else { 378 | strcpy( 379 | message 380 | , "Expected exactly one string type parameter" 381 | ); 382 | return 1; 383 | } 384 | } 385 | void sys_eval_deinit( 386 | UDF_INIT *initid 387 | ){ 388 | } 389 | char* sys_eval( 390 | UDF_INIT *initid 391 | , UDF_ARGS *args 392 | , char* result 393 | , unsigned long* length 394 | , char *is_null 395 | , char *error 396 | ){ 397 | FILE *pipe; 398 | char line[1024]; 399 | unsigned long outlen, linelen; 400 | 401 | result = malloc(1); 402 | outlen = 0; 403 | 404 | pipe = popen(args->args[0], "r"); 405 | 406 | while (fgets(line, sizeof(line), pipe) != NULL) { 407 | linelen = strlen(line); 408 | result = realloc(result, outlen + linelen); 409 | strncpy(result + outlen, line, linelen); 410 | outlen = outlen + linelen; 411 | } 412 | 413 | pclose(pipe); 414 | 415 | if (!(*result) || result == NULL) { 416 | *is_null = 1; 417 | } else { 418 | result[outlen] = 0x00; 419 | *length = strlen(result); 420 | } 421 | 422 | return result; 423 | } 424 | 425 | 426 | #endif /* HAVE_DLOPEN */ 427 | -------------------------------------------------------------------------------- /WPM_Latch/latch_sdk/Latch.rb: -------------------------------------------------------------------------------- 1 | #Latch Ruby SDK - Set of reusable classes to allow developers integrate Latch on their applications. 2 | #Copyright (C) 2013 Eleven Paths 3 | # 4 | #This library is free software; you can redistribute it and/or 5 | #modify it under the terms of the GNU Lesser General Public 6 | #License as published by the Free Software Foundation; either 7 | #version 2.1 of the License, or (at your option) any later version. 8 | # 9 | #This library is distributed in the hope that it will be useful, 10 | #but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | #Lesser General Public License for more details. 13 | # 14 | #You should have received a copy of the GNU Lesser General Public 15 | #License along with this library; if not, write to the Free Software 16 | #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | 19 | require 'base64' 20 | require 'cgi' 21 | require 'openssl' 22 | require 'net/http' 23 | require_relative 'LatchResponse' 24 | 25 | class Latch 26 | 27 | attr_accessor :api_host 28 | API_HOST = "https://latch.elevenpaths.com" 29 | API_VERSION = "0.9" 30 | API_CHECK_STATUS_URL = "/api/"+API_VERSION+"/status" 31 | API_PAIR_URL = "/api/"+API_VERSION+"/pair" 32 | API_PAIR_WITH_ID_URL = "/api/"+API_VERSION+"/pairWithId" 33 | API_UNPAIR_URL = "/api/"+API_VERSION+"/unpair" 34 | API_LOCK_URL = "/api/"+API_VERSION+"/lock" 35 | API_UNLOCK_URL = "/api/"+API_VERSION+"/unlock" 36 | API_HISTORY_URL = "/api/"+API_VERSION+"/history" 37 | API_OPERATIONS_URL = "/api/"+API_VERSION+"/operation" 38 | 39 | 40 | AUTHORIZATION_HEADER_NAME = "Authorization" 41 | DATE_HEADER_NAME = "X-11Paths-Date" 42 | AUTHORIZATION_METHOD = "11PATHS" 43 | AUTHORIZATION_HEADER_FIELD_SEPARATOR = " " 44 | 45 | HMAC_ALGORITHM = "sha1" 46 | 47 | X_11PATHS_HEADER_PREFIX = "X-11Paths-" 48 | X_11PATHS_HEADER_SEPARATOR = ":" 49 | 50 | 51 | 52 | 53 | 54 | # The custom header consists of three parts, the method, the appId and the signature. 55 | # This method returns the specified part if it exists. 56 | # @param $part The zero indexed part to be returned 57 | # @param $header The HTTP header value from which to extract the part 58 | # @return string the specified part from the header or an empty string if not existent 59 | def getPartFromHeader(part, header) 60 | if (header.empty?) 61 | parts = header.split(AUTHORIZATION_HEADER_FIELD_SEPARATOR) 62 | if(parts.length > part) 63 | return parts[part] 64 | end 65 | end 66 | return "" 67 | end 68 | 69 | # @param $authorizationHeader Authorization HTTP Header 70 | # @return string the Authorization method. Typical values are "Basic", "Digest" or "11PATHS" 71 | def getAuthMethodFromHeader(authorizationHeader) 72 | getPartFromHeader(0, authorizationHeader) 73 | end 74 | 75 | # @param $authorizationHeader Authorization HTTP Header 76 | # @return string the requesting application Id. Identifies the application using the API 77 | def getAppIdFromHeader(authorizationHeader) 78 | getPartFromHeader(1, authorizationHeader) 79 | end 80 | 81 | 82 | # @param $authorizationHeader Authorization HTTP Header 83 | # @return string the signature of the current request. Verifies the identity of the application using the API 84 | def getSignatureFromHeader(authorizationHeader) 85 | getPartFromHeader(2, authorizationHeader) 86 | end 87 | 88 | 89 | # Create an instance of the class with the Application ID and secret obtained from Eleven Paths 90 | # @param $appId 91 | # @param $secretKey 92 | def initialize(appid, secret) 93 | @appid = appid 94 | @secret = secret 95 | @api_host = API_HOST 96 | end 97 | 98 | def http(method, url, headers, params=nil) 99 | uri = URI.parse(url) 100 | http = Net::HTTP.new(uri.host, uri.port) 101 | 102 | if (uri.default_port == 443) 103 | http.use_ssl = true 104 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE 105 | end 106 | 107 | if(method == "GET") 108 | request = Net::HTTP::Get.new(uri.request_uri) 109 | elsif (method == 'POST') 110 | request = Net::HTTP::Post.new(uri.request_uri) 111 | request.set_form_data(params) 112 | elsif (method == "PUT") 113 | request = Net::HTTP::Put.new(uri.request_uri) 114 | request.set_form_data(params) 115 | elsif (method == "DELETE") 116 | request = Net::HTTP::Delete.new(uri.request_uri) 117 | end 118 | 119 | headers.map do |key,value| 120 | request[key] = value 121 | end 122 | 123 | response = http.request(request) 124 | response.body 125 | end 126 | 127 | 128 | def http_get_proxy(url) 129 | LatchResponse.new(http("GET", api_host + url, authenticationHeaders('GET', url, nil))) 130 | end 131 | 132 | def http_post_proxy(url, params) 133 | LatchResponse.new(http("POST", api_host + url, authenticationHeaders('POST', url, nil, nil, params), params)) 134 | end 135 | 136 | def http_put_proxy(url, params) 137 | LatchResponse.new(http("PUT", api_host + url, authenticationHeaders('PUT', url, nil, nil, params), params)) 138 | end 139 | 140 | def http_delete_proxy(url) 141 | LatchResponse.new(http("DELETE", api_host + url, authenticationHeaders('DELETE', url, nil))) 142 | end 143 | 144 | def pairWithId(accountId) 145 | http_get_proxy(API_PAIR_WITH_ID_URL + '/' + accountId) 146 | end 147 | 148 | 149 | def pair(token) 150 | http_get_proxy(API_PAIR_URL + '/' + token) 151 | end 152 | 153 | 154 | def status(accountId) 155 | http_get_proxy(API_CHECK_STATUS_URL + '/' + accountId) 156 | end 157 | 158 | 159 | def operationStatus(accountId, operationId) 160 | http_get_proxy(API_CHECK_STATUS_URL + "/" + accountId + '/op/' + operationId) 161 | end 162 | 163 | 164 | def unpair(accountId) 165 | http_get_proxy(API_UNPAIR_URL + '/' + accountId) 166 | end 167 | 168 | def lock(accountId, operationId=nil) 169 | if (operationId == nil) 170 | http_post_proxy(API_LOCK_URL + '/' + accountId, {}) 171 | else 172 | http_post_proxy(API_LOCK_URL + '/' + accountId + '/op/' + operationId, {}) 173 | end 174 | end 175 | 176 | def unlock(accountId, operationId=nil) 177 | if (operationId == nil) 178 | http_post_proxy(API_UNLOCK_URL + '/' + accountId, {}) 179 | else 180 | http_post_proxy(API_UNLOCK_URL + '/' + accountId + '/op/' + operationId, {}) 181 | end 182 | end 183 | 184 | def history (accountId, from='0', to=nil) 185 | if (to == nil) 186 | to = Time.now.to_i*1000 187 | end 188 | http_get_proxy(API_HISTORY_URL + '/' + accountId + '/' + from + '/' + to.to_s) 189 | end 190 | 191 | def createOperation(parentId, name, twoFactor, lockOnRequest) 192 | params = { 'parentId' => parentId, 'name' => name, 'two_factor'=>twoFactor, 'lock_on_request'=>lockOnRequest} 193 | http_put_proxy(API_OPERATIONS_URL, params) 194 | end 195 | 196 | def updateOperation(operationId, name, twoFactor, lockOnRequest) 197 | params = { 'name' => name, 'two_factor'=>twoFactor, 'lock_on_request'=>lockOnRequest} 198 | http_post_proxy(API_OPERATIONS_URL + '/' + operationId, params) 199 | end 200 | 201 | def deleteOperation(operationId) 202 | http_delete_proxy(API_OPERATIONS_URL + '/' + operationId) 203 | end 204 | 205 | def getOperations(operationId=nil) 206 | if (operationId == nil) 207 | http_get_proxy(API_OPERATIONS_URL) 208 | else 209 | http_get_proxy(API_OPERATIONS_URL + '/' + operationId) 210 | end 211 | end 212 | 213 | # @param $data the string to sign 214 | # @return string base64 encoding of the HMAC-SHA1 hash of the data parameter using {@code secretKey} as cipher key. 215 | def signData(data) 216 | Base64.encode64(OpenSSL::HMAC.digest(HMAC_ALGORITHM, @secret, data)) 217 | end 218 | 219 | 220 | # Calculate the authentication headers to be sent with a request to the API 221 | # @param $HTTPMethod the HTTP Method, currently only GET is supported 222 | # @param $queryString the urlencoded string including the path (from the first forward slash) and the parameters 223 | # @param $xHeaders HTTP headers specific to the 11-paths API. null if not needed. 224 | # @param $utc the Universal Coordinated Time for the Date HTTP header 225 | # @return array a map with the Authorization and Date headers needed to sign a Latch API request 226 | def authenticationHeaders(httpMethod, queryString, xHeaders=nil, utc=nil, params=nil) 227 | if (utc == nil) 228 | utc = getCurrentUTC 229 | end 230 | 231 | stringToSign = (httpMethod.upcase).strip + "\n" + 232 | utc.to_s + "\n" + 233 | getSerializedHeaders(xHeaders) + "\n" + 234 | queryString.strip 235 | 236 | if (params != nil && params.size > 0) 237 | serializedParams = getSerializedParams(params) 238 | if (serializedParams != nil && serializedParams.size > 0) 239 | stringToSign = stringToSign.strip + "\n" + serializedParams 240 | end 241 | end 242 | 243 | authorizationHeader = AUTHORIZATION_METHOD + 244 | AUTHORIZATION_HEADER_FIELD_SEPARATOR + 245 | @appid + 246 | AUTHORIZATION_HEADER_FIELD_SEPARATOR + 247 | signData(stringToSign).chop 248 | 249 | headers = {} 250 | headers[AUTHORIZATION_HEADER_NAME] = authorizationHeader 251 | headers[DATE_HEADER_NAME] = utc 252 | return headers 253 | end 254 | 255 | 256 | 257 | # Prepares and returns a string ready to be signed from the 11-paths specific HTTP headers received 258 | # @param $xHeaders a non necessarily ordered map of the HTTP headers to be ordered without duplicates. 259 | # @return a String with the serialized headers, an empty string if no headers are passed, or null if there's a problem 260 | # such as non 11paths specific headers 261 | def getSerializedHeaders(xHeaders) 262 | if(xHeaders != nil) 263 | headers = xHeaders.inject({}) do |xHeaders, keys| 264 | hash[keys[0].downcase] = keys[1] 265 | hash 266 | end 267 | 268 | 269 | serializedHeaders = '' 270 | 271 | headers.sort.map do |key,value| 272 | if(key.downcase == X_11PATHS_HEADER_PREFIX.downcase) 273 | puts "Error serializing headers. Only specific " + X_11PATHS_HEADER_PREFIX + " headers need to be singed" 274 | return nil 275 | end 276 | serializedHeaders += key + X_11PATHS_HEADER_SEPARATOR + value + ' ' 277 | end 278 | substitute = 'utf-8' 279 | return serializedHeaders.gsub(/^[#{substitute}]+|[#{substitute}]+$/, '') 280 | else 281 | return "" 282 | end 283 | end 284 | 285 | def getSerializedParams(parameters) 286 | if (parameters != nil) 287 | serializedParams = '' 288 | 289 | parameters.sort.map do |key,value| 290 | serializedParams += key + "=" + value + '&' 291 | end 292 | substitute = '&' 293 | return serializedParams.gsub(/^[#{substitute}]+|[#{substitute}]+$/, '') 294 | else 295 | return "" 296 | end 297 | end 298 | 299 | # @return a string representation of the current time in UTC to be used in a Date HTTP Header 300 | def getCurrentUTC 301 | Time.now.utc 302 | end 303 | end 304 | -------------------------------------------------------------------------------- /WPM_Latch/lib_mysqludf_sys/lib_mysqludf_sys.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | lib_mysqludf_sys - A library of MySQL UDFs for working with the environment in which MySQL runs 8 | 9 | 10 |
11 | Top 12 | | Up 13 |
14 |

lib_mysqludf_sys

15 |
16 | Documentation 17 | | Binary 18 | | Installation 19 | | Source 20 | | tar.gz 21 |
22 |

23 | This library lib_mysqludf_sys contains a number of functions that allows one to interact with the operating system. 24 |

25 |
    26 |
  1. sys_eval - executes an arbitrary command, and returns it's output.
  2. 27 |
  3. sys_exec - executes an arbitrary command, and returns it's exit code.
  4. 28 |
  5. sys_get - gets the value of an environment variable.
  6. 29 |
  7. sys_set - create an environment variable, or update the value of an existing environment variable.
  8. 30 |
31 |

32 | Use lib_mysqludf_sys_info() to obtain information about the currently installed version of lib_mysqludf_sys. 33 |

34 | 35 | 36 |

sys_eval

37 |

38 | sys_eval takes one command string argument and executes it, returning its output. 39 |

40 |

Syntax

41 |
sys_eval(arg1)
42 |

Parameters and Return Values

43 |
44 |
arg1
45 |
46 | A command string valid for the current operating system or execution environment. 47 |
48 |
returns
49 |
50 | Whatever output the command pushed to the standard output stream. 51 |
52 |
53 |

Installation

54 |

55 | Place the shared library binary in an appropriate location. 56 | Log in to mysql as root or as another user with sufficient privileges, and select any database. 57 | Then, create the function using the following DDL statement: 58 |

59 |
 60 | CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so';	
 61 | 	
62 |

63 | The function will be globally available in all databases. 64 |

65 |

66 | The deinstall the function, run the following statement: 67 |

68 |
 69 | DROP FUNCTION sys_eval;
 70 | 	
71 |

Examples

72 |

73 | None yet 74 |

75 |

A Note of Caution

76 |

77 | Be very careful in deciding whether you need this function. 78 | UDFs are available to all database users - you cannot grant EXECUTE privileges for them. 79 | As the commandstring passed to sys_exec can do pretty much everything, 80 | exposing the function poses a very real security hazard. 81 |

82 |

83 | Even for a benign user, it is possible to accidentally do a lot of damage with it. 84 | The call will be executed with the privileges of the os user that runs MySQL, 85 | so it is entirely feasible to delete MySQL's data directory, or worse. 86 |

87 |

88 | The function is intended for specialized MySQL applications where one needs extended 89 | control over the operating system. 90 | Currently, we do not have UDF's for ftp, email and http, 91 | and this function can be used to implement such functionality in case it is really necessary 92 | (datawarehouse staging areas could be a case in example). 93 |

94 |

95 | You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this. 96 |

97 |

98 | If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using AppArmor. 99 |

100 | 101 |

sys_exec

102 |

103 | sys_exec takes one command string argument and executes it. 104 |

105 |

Syntax

106 |
sys_exec(arg1)
107 |

Parameters and Return Values

108 |
109 |
arg1
110 |
111 | A command string valid for the current operating system or execution environment. 112 |
113 |
returns
114 |
115 | An (integer) exit code returned by the executed process. 116 |
117 |
118 |

Installation

119 |

120 | Place the shared library binary in an appropriate location. 121 | Log in to mysql as root or as another user with sufficient privileges, and select any database. 122 | Then, create the function using the following DDL statement: 123 |

124 |
125 | CREATE FUNCTION sys_exec RETURNS INT SONAME 'lib_mysqludf_sys.so';	
126 | 	
127 |

128 | The function will be globally available in all databases. 129 |

130 |

131 | The deinstall the function, run the following statement: 132 |

133 |
134 | DROP FUNCTION sys_exec;
135 | 	
136 |

Examples

137 |

138 | None yet 139 |

140 |

A Note of Caution

141 |

142 | Be very careful in deciding whether you need this function. 143 | UDFs are available to all database users - you cannot grant EXECUTE privileges for them. 144 | As the commandstring passed to sys_exec can do pretty much everything, 145 | exposing the function poses a very real security hazard. 146 |

147 |

148 | Even for a benign user, it is possible to accidentally do a lot of damage with it. 149 | The call will be executed with the privileges of the os user that runs MySQL, 150 | so it is entirely feasible to delete MySQL's data directory, or worse. 151 |

152 |

153 | The function is intended for specialized MySQL applications where one needs extended 154 | control over the operating system. 155 | Currently, we do not have UDF's for ftp, email and http, 156 | and this function can be used to implement such functionality in case it is really necessary 157 | (datawarehouse staging areas could be a case in example). 158 |

159 |

160 | You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this. 161 |

162 |

163 | If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using AppArmor. 164 |

165 |

sys_get

166 |

167 | sys_get takes the name of an environment variable and returns the value of the variable. 168 |

169 |

Syntax

170 |
sys_get([arg1)
171 |

Parameters and Return Values

172 |
173 |
arg1
174 |
175 | A string that denotes the name of an environment value. 176 |
177 |
returns
178 |
179 | If the variable exists, a string containing the value of the environment variable. 180 | If the variable does not exist, the function return NULL. 181 |
182 |
183 |

Installation

184 |

185 | Place the shared library binary in an appropriate location. 186 | Log in to mysql as root or as another user with sufficient privileges, and select any database. 187 | Then, create the function using the following DDL statement: 188 |

189 |
190 | CREATE FUNCTION sys_get RETURNS STRING SONAME 'lib_mysqludf_sys.so';	
191 | 	
192 |

193 | The function will be globally available in all databases. 194 |

195 |

196 | The deinstall the function, run the following statement: 197 |

198 |
199 | DROP FUNCTION sys_get;
200 | 	
201 |

Examples

202 |

203 | None yet 204 |

205 |

A Note of Caution

206 |

207 | Be very careful in deciding whether you need this function. 208 | UDFs are available to all database users - you cannot grant EXECUTE privileges for them. 209 | The variables known in the environment where mysql runs are freely accessible using this function. 210 | Any user can get access to potentially secret information, such as 211 | the user that is running mysqld, the path of the user's home directory etc. 212 |

213 |

214 | The function is intended for specialized MySQL applications where one needs extended 215 | control over the operating system. 216 |

217 |

218 | You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this. 219 |

220 |

sys_set

221 |

222 | sys_get takes the name of an environment variable and returns the value of the variable. 223 |

224 |

Syntax

225 |
sys_set([arg1, arg2)
226 |

Parameters and Return Values

227 |
228 |
arg1
229 |
230 | A string that denotes the name of an environment value. 231 |
232 |
arg2
233 |
234 | An expression that contains the value that is to be assigned to the environment variable. 235 |
236 |
returns
237 |
238 | 0 if the assignment or creation succeed. 239 | non-zero otherwise. 240 |
241 |
242 |

Installation

243 |

244 | Place the shared library binary in an appropriate location. 245 | Log in to mysql as root or as another user with sufficient privileges, and select any database. 246 | Then, create the function using the following DDL statement: 247 |

248 |
249 | CREATE FUNCTION sys_set RETURNS STRING SONAME 'lib_mysqludf_sys.so';	
250 | 	
251 |

252 | The function will be globally available in all databases. 253 |

254 |

255 | The deinstall the function, run the following statement: 256 |

257 |
258 | DROP FUNCTION sys_set;
259 | 	
260 |

Examples

261 |

262 | None yet 263 |

264 |

A Note of Caution

265 |

266 | Be very careful in deciding whether you need this function. 267 | UDFs are available to all database users - you cannot grant EXECUTE privileges for them. 268 | This function will overwrite existing environment variables. 269 |

270 |

271 | The function is intended for specialized MySQL applications where one needs extended 272 | control over the operating system. 273 |

274 |

275 | You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this. 276 |

277 | 278 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | --------------------------------------------------------------------------------