├── .htaccess
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── LICENSE.3RDPARTY
├── README.md
├── config
└── fsl_config.php
├── controllers
├── deck
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── deck
│ └── kong.yaml
└── fsl_controllers.php
├── examples
├── dadjokes.yaml
└── docker-compose.yaml
├── index.php
├── lib
├── 3rd_party_helpers
│ ├── Medoo.php
│ ├── jwt_helper.php
│ ├── password_helper.php
│ └── xss_filter.class.php
├── fsl.php
├── fsl_functions.php
└── limonade
│ ├── public
│ ├── css
│ │ └── screen.css
│ └── img
│ │ ├── 404.gif
│ │ └── fsl_logo.png
│ └── views
│ ├── _debug.html.php
│ ├── _notices.html.php
│ ├── default_layout.php
│ └── error.html.php
├── public
├── banner-fsl.png
├── favicon.ico
├── fsl.jpeg
├── fsl_logo.png
├── kongmap2.png
├── kongmap3.png
├── launchpage.png
├── soda_glass.jpg
└── soda_glass.thb.jpg
├── screenshots
├── kongmap-deck.png
├── kongmap-endpoint.png
└── kongmap-home.png
└── views
├── fsl_default_layout.php
└── mapview.php
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | Options +FollowSymlinks
3 | Options +Indexes
4 | RewriteEngine on
5 |
6 | # set directory to FSL Install if your app is in a subfolder else set this to /
7 | RewriteBase /
8 |
9 | # test string is a valid files
10 | RewriteCond %{SCRIPT_FILENAME} !-f
11 | # test string is a valid directory
12 | RewriteCond %{SCRIPT_FILENAME} !-d
13 |
14 | RewriteRule ^(.*)$ index.php?uri=/$1 [NC,L,QSA]
15 | # with QSA flag (query string append),
16 | # forces the rewrite engine to append a query string part of the
17 | # substitution string to the existing string, instead of replacing it.
18 |
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 20210706
2 | ### Added
3 | - None
4 | ### Changed
5 | - Updated: misc UI change to map view
6 | - Fixed: Navbar issues. Updated style.
7 | ### Removed
8 | - None
9 |
10 |
11 | ## 20210706
12 | ### Added
13 | - None
14 | ### Changed
15 | - Fixed: Changed default ports to high ports. Docker image no longer uses ports that require root privilege to run - https://github.com/yesinteractive/kong-map/issues/20
16 | - Fixed: Mixed content on view/edit cluster - https://github.com/yesinteractive/kong-map/issues/15
17 | - Fixed: fsl_curl return 0 when Kong admin port is https - https://github.com/yesinteractive/kong-map/issues/19
18 | - Updated Kong decK version to 1.7.0.
19 | ### Removed
20 | - None
21 |
22 |
23 | ## 20210329
24 | ### Added
25 | - None
26 | ### Changed
27 | - Updated Kong decK version to 1.5.1.
28 | ### Removed
29 | - None
30 |
31 |
32 | ## 20210120
33 | ### Added
34 | - None
35 | ### Changed
36 | - Fixed: Pop-ups don't show content correctly in map view: https://github.com/yesinteractive/kong-map/issues/10
37 | ### Removed
38 | - None
39 |
40 | ## 20201218
41 | ### Added
42 | - None
43 | ### Changed
44 | - Fixed Declarative configs were not displaying in editor for Kong Enterprise 2.2 on the default workspace. This has been resolved.
45 | ### Removed
46 | - None
47 |
48 | ## 20201109
49 | ### Added
50 | - Counts for Kong entities (services, routes, plugins) on Cluster Map cluster entity.
51 | - Route Analyzer now shows upstream targets configured for a service.
52 | ### Changed
53 | - Fixed Export Config with ID button function. Both buttons were previously exporting without ID's only.
54 | ### Removed
55 | - None
56 |
57 |
58 | ## 20201106
59 | ### Added
60 | - Ability to edit specific routes, plugins, and services directly from cluster map view. Click on map node
61 | to reveal the edit button. Clicking the edit button will open the config editor and highlight the element to be directly edited in the config.
62 | - Ability to edit specific routes, plugins, and services in route analyzer. Clicking the edit button
63 | will open the config editor and highlight the element to be directly edited in the config.
64 | - Toggle to view declarative config with or with entity ID's
65 | ### Changed
66 | - The `kong_ent_manager_url` JSON parameter when set to `null` will hide the Kong Manager buttons
67 | form KongMap for that cluster, even though the cluster is an enterprise cluster.
68 | - Export buttons to offer options to export with or without entity ID's.
69 | ### Removed
70 | - Kong Logo from KongMap header.
71 |
72 |
73 | ## 20201101
74 | ### Added
75 | - Docker compose install examples.
76 | - Tags, which are now searchable, to all routes and services nodes in cluster map.
77 | ### Changed
78 | - Filter in cluster view can search and filter to all details of an element of map such as tag name, or url or a service, etc. Previously could only filter on node name.
79 | - Fixed word wrap issues in web app view template.
80 | - Added Kong, Inc. trademark disclaimers.
81 | - Other misc page formatting.
82 | ### Removed
83 | -None
84 |
85 |
86 | ## 20201026
87 | ### Added
88 | - Confirmation dialog when about to save new declarative configuration.
89 | - Enhancement Request - Make map searchable. Will enhance this feature further in future. For now acts as a filter rather than proper search and highlight. https://github.com/yesinteractive/kong-map/issues/2
90 |
91 | ### Changed
92 | - Altered cluster details displayable data in cluster view
93 | - Altered key value data appearance in cluster/map view
94 |
95 | ### Removed
96 | - None
97 |
98 |
99 | ## 20201022
100 | ### Added
101 | - None
102 |
103 | ### Changed
104 | - Fixed - Custom plugin throws error when analyzing endpoint]) https://github.com/yesinteractive/kong-map/issues/1
105 | - Updated Config Editor buttons and restyled some UI elements
106 |
107 | ### Removed
108 | - None
109 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.11
2 | MAINTAINER YesInteractive- http://yes-interactive.com
3 |
4 | # Install modules and updates
5 | RUN apk update \
6 | && apk --no-cache add \
7 | openssl \
8 | apache2 \
9 | apache2-ssl \
10 | apache2-http2 \
11 | git \
12 | unzip \
13 | # Install PHP from community
14 | && apk --no-cache --repository http://dl-4.alpinelinux.org/alpine/v3.11/community/ add \
15 | php7=="7.3.22-r0" \
16 | php7-apache2 \
17 | php7-bcmath \
18 | php7-bz2 \
19 | php7-calendar \
20 | php7-common \
21 | php7-ctype \
22 | php7-curl \
23 | php7-dom \
24 | php7-json \
25 | php7-mbstring \
26 | php7-mcrypt \
27 | php7-memcached \
28 | php7-mysqlnd \
29 | php7-opcache \
30 | php7-openssl \
31 | php7-pdo \
32 | php7-pdo_mysql \
33 | php7-pdo_sqlite \
34 | php7-phar \
35 | php7-session \
36 | php7-sockets \
37 | php7-xml \
38 | php7-xmlreader \
39 | && rm /var/cache/apk/* \
40 |
41 | # Run required config / setup for apache
42 | # Ensure apache can create pid file
43 | #&& mkdir /run/apache2 \
44 | # Fix group
45 | && sed -i -e 's/Group apache/Group www-data/g' /etc/apache2/httpd.conf \
46 | # Fix ssl module
47 | && sed -i -e 's/LoadModule ssl_module lib\/apache2\/mod_ssl.so/LoadModule ssl_module modules\/mod_ssl.so/g' /etc/apache2/conf.d/ssl.conf \
48 | && sed -i -e 's/LoadModule socache_shmcb_module lib\/apache2\/mod_socache_shmcb.so/LoadModule socache_shmcb_module modules\/mod_socache_shmcb.so/g' /etc/apache2/conf.d/ssl.conf \
49 | # Enable modules
50 | && sed -i -e 's/#LoadModule rewrite_module modules\/mod_rewrite.so/LoadModule rewrite_module modules\/mod_rewrite.so/g' /etc/apache2/httpd.conf \
51 | # Change document root to /app
52 | && mkdir /app && chown -R apache:apache /app \
53 | && sed -i -e 's/\/var\/www\/localhost\/htdocs/\/app/g' /etc/apache2/httpd.conf \
54 | && sed -i -e 's/\/var\/www\/localhost\/htdocs/\/app/g' /etc/apache2/conf.d/ssl.conf \
55 | # moved apache logging to stdout and stderr
56 | && sed -i -e 's/ErrorLog logs\/error.log/ErrorLog \/dev\/stderr/g' /etc/apache2/httpd.conf \
57 | && sed -i -e 's/CustomLog logs\/access.log combined/CustomLog \/dev\/stdout common/g' /etc/apache2/httpd.conf \
58 | && sed -i -e 's/ErrorLog logs\/ssl_error.log/ErrorLog \/dev\/stderr/g' /etc/apache2/conf.d/ssl.conf \
59 | && sed -i -e 's/TransferLog logs\/ssl_access.log/TransferLog \/dev\/stdout/g' /etc/apache2/conf.d/ssl.conf \
60 | && sed -i -e 's/CustomLog logs\/ssl_request.log/#CustomLog \/dev\/stdout/g' /etc/apache2/conf.d/ssl.conf \
61 | # Change default ports
62 | && sed -i -e 's/Listen 80/Listen 8100/g' /etc/apache2/httpd.conf \
63 | && sed -i -e 's/443/8143/g' /etc/apache2/conf.d/ssl.conf \
64 | # Allow for custom apache configs
65 | && mkdir /etc/apache2/conf.d/custom \
66 | && echo '' >> /etc/apache2/httpd.conf \
67 | && echo 'IncludeOptional /etc/apache2/conf.d/custom/*.conf' >> /etc/apache2/httpd.conf \
68 | # Fix modules
69 | && sed -i 's#AllowOverride None#AllowOverride All#' /etc/apache2/httpd.conf \
70 | && sed -i -e 's/ServerRoot \/var\/www/ServerRoot \/etc\/apache2/g' /etc/apache2/httpd.conf \
71 | && mv /var/www/modules /etc/apache2/modules \
72 | && mv /var/www/run /etc/apache2/run \
73 | && mv /var/www/logs /etc/apache2/logs \
74 | # Empty /var/www and add an index.php to show phpinfo()
75 | && rm -rf /var/www/* \
76 | && echo '' > /app/phpinfo.php \
77 | && wget --header '' https://github.com/yesinteractive/kong-map/archive/main.zip -P /app \
78 | && unzip /app/main.zip -d /app \
79 | && rm -rf /app/main.zip \
80 | && cp -r /app/kong-map-main/. /app \
81 | && rm -rf /app/kong-map-main \
82 | && chmod 777 /app/controllers/deck/kong.yaml
83 |
84 | WORKDIR /app
85 |
86 | # Export http and https
87 | EXPOSE 8100 8143
88 |
89 | # Run apache in foreground
90 | CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
91 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 yes!nteractive, llc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.3RDPARTY:
--------------------------------------------------------------------------------
1 | KongMap is made possible by the following open source projects:
2 |
3 | ===============================================
4 | ===============================================
5 | ===============================================
6 | FSL
7 | https://github.com/yesinteractive/fsl
8 | *
9 | * @author Fabrice Luraine
10 | * @copyright Copyright (c) 2018 Yes Interactive, LLC
11 | * @license http://opensource.org/licenses/mit-license.php The MIT License
12 | * @package limonade
13 |
14 | MIT License
15 |
16 | Copyright (c) 2018 Yes Interactive, LLC
17 |
18 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
21 |
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | ===============================================
25 | ===============================================
26 | ===============================================
27 | L I M O N A D E
28 | https://github.com/sofadesign/limonade
29 | *
30 | * @author Fabrice Luraine
31 | * @copyright Copyright (c) 2009 Fabrice Luraine
32 | * @license http://opensource.org/licenses/mit-license.php The MIT License
33 | * @package limonade
34 |
35 | The MIT License (MIT)
36 |
37 | Copyright (c) 2009 Fabrice Luraine
38 |
39 | Permission is hereby granted, free of charge, to any person
40 | obtaining a copy of this software and associated documentation
41 | files (the "Software"), to deal in the Software without
42 | restriction, including without limitation the rights to use,
43 | copy, modify, merge, publish, distribute, sublicense, and/or sell
44 | copies of the Software, and to permit persons to whom the
45 | Software is furnished to do so, subject to the following
46 | conditions:
47 |
48 | The above copyright notice and this permission notice shall be
49 | included in all copies or substantial portions of the Software.
50 |
51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
52 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
53 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
54 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
55 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
56 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
57 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
58 | OTHER DEALINGS IN THE SOFTWARE.
59 |
60 | ===============================================
61 | ===============================================
62 | ===============================================
63 | PHP XSS Filter
64 | https://github.com/JBlond/PHP-XSS-Filter
65 | *
66 | * @author mario.brandt
67 | * @copyright Copyright (c) 2013 - 2017
68 |
69 | The MIT License (MIT)
70 |
71 | Copyright (c) 2013 - 2017 Mario
72 |
73 | Permission is hereby granted, free of charge, to any person obtaining a copy of
74 | this software and associated documentation files (the "Software"), to deal in
75 | the Software without restriction, including without limitation the rights to
76 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
77 | the Software, and to permit persons to whom the Software is furnished to do so,
78 | subject to the following conditions:
79 |
80 | The above copyright notice and this permission notice shall be included in all
81 | copies or substantial portions of the Software.
82 |
83 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
84 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
85 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
86 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
87 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
88 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
89 |
90 | ===============================================
91 | ===============================================
92 | ===============================================
93 | Popper.js
94 | https://github.com/FezVrasta/popper.js
95 | *
96 | * @fileOverview Kickass library to create and place poppers near their reference elements.
97 | * @version ${require('./package.json').version}
98 | * @license
99 | * Copyright (c) 2016 Federico Zivolo and contributors
100 |
101 | The MIT License (MIT)
102 | =====================
103 |
104 | Copyright © 2016 Federico Zivolo and contributors
105 |
106 | Permission is hereby granted, free of charge, to any person
107 | obtaining a copy of this software and associated documentation
108 | files (the “Software”), to deal in the Software without
109 | restriction, including without limitation the rights to use,
110 | copy, modify, merge, publish, distribute, sublicense, and/or sell
111 | copies of the Software, and to permit persons to whom the
112 | Software is furnished to do so, subject to the following
113 | conditions:
114 |
115 | The above copyright notice and this permission notice shall be
116 | included in all copies or substantial portions of the Software.
117 |
118 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
119 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
120 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
121 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
122 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
123 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
124 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
125 | OTHER DEALINGS IN THE SOFTWARE.
126 |
127 | ===============================================
128 | ===============================================
129 | ===============================================
130 | Medoo database framework
131 | https://medoo.in
132 | * Version 1.6
133 | *
134 | * Copyright 2018, Angel Lai
135 | * Released under the MIT license
136 | *
137 |
138 | MIT License
139 |
140 | Copyright (c) 2018 Angel Lai
141 |
142 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
143 |
144 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
145 |
146 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KongMap #
2 | Kongmap is a free visualization tool which allows you to view and declaratively edit configurations of
3 | your Kong API Gateway Clusters, including Routes, Services, and Plugins/Policies. The tool is
4 | available for installation on Docker and Kubernetes only at this time.
5 |
6 | [View list of latest changes/updates here.](https://github.com/yesinteractive/kong-map/blob/main/CHANGELOG.md)
7 |
8 | 
9 | [](https://hub.docker.com/r/yesinteractive/kongmap)
10 | [](https://github.com/yesinteractive/kong-map/blob/main/CHANGELOG.md)
11 |
12 | - [Features](#Features)
13 | - [Cluster View](#Cluster-View)
14 | - [Endpoint Analyzer](#Endpoint-Analyzer)
15 | - [Declarative Configuration Viewer/Editor](#Declarative-Configuration-Viewer-Editor)
16 | - [Compatibility](#Compatibility)
17 | - [Docker Installation](#Docker-Installation)
18 | - [Questions and Feedback](#Feedback-and-Issues)
19 |
20 | ## Features
21 |
22 | #### Cluster View
23 | Allows an admin to view a dynamic map of their Kong API Gateway clusters and visually see relationships between
24 | Workspaces (for Kong Enterprise), Services, Routes (Endpoints), and Plugins (Policies). Cluster view can also
25 | be used to see configuration of the proxy plane of your Kong for Kubernetes Ingress Controller. Clicking on any
26 | entity displays details of the entity and related links. Plugins can be toggled from view and map is searchable
27 | (search by entity name, Kong tag, workspace, url, or any other details related to a Kong entity.)
28 |
29 | If editing is enabled, any Kong entity can be edited from the Cluster View map. Clicking on the edit button from
30 | any entity will send user directly to that entity in the declarative editor.
31 |
32 |
33 | 
34 |
35 | #### Endpoint Analyzer
36 | View details of an API Endpoint (Route). The analyzer shows the Service attached to the endpoint/route as well as provides
37 | a breakdown of all plugins/policies in order of execution attached to the route/endpoint. For Kong Enterprise users,
38 | all entities can be viewed directly via a link to Kong Manager.
39 |
40 | If editing is enabled, any Kong entity can be edited from the Endpoint Analyzer map. Clicking on the edit button from
41 | any entity will send user directly to that entity in the declarative editor.
42 |
43 | 
44 |
45 |
46 | #### Declarative Configuration Viewer Editor
47 | KongMap is deployed with a browser based implementation of Kong's CLI tool, decK. Here you can view, edit, and export
48 | Kong declarative configurations for your open source and Enterprise clusters via YAML. Configurations can easily
49 | be copied and pasted from one Kong cluster to another or between workspaces. Declarative
50 | configuration editing can be disabled by KongMap configuration, or managed via RBAC permissions if using Kong Enterprise.
51 |
52 | The Viewer/Editor can be invoked from the Cluster Map view by clicking on on any Kong entity, and from
53 | any element from the Endpoint Analyzer. Kong entity ID's can be toggled in and out of view with the viewer/editor.
54 |
55 | 
56 |
57 | ## Compatibility
58 | KongMap supports both Kong Open Source and Kong Enterprise Clusters greater than version 1.3 and supports both DB and Non-DB (dbless) Kong configurations.
59 | KongMap also supports Kong for Kubernetes Ingress Controller versions greater than 0.5 (In Kong for Kubernetes,
60 | the Ingress Controller's proxy container must have its Admin API exposed in some fashion.)
61 |
62 | KongMap uses various public CDN's for various UI elements such as Bootstrap, jQuery, etc. so KongMap will not display
63 | correctly in a browser on a closed network without Internet access.
64 |
65 | ## Docker Installation
66 |
67 | Docker image is Alpine 3.11 based running PHP 7.3 on Apache. The container exposes both ports 8100 an 8143 with a self signed certificated.
68 |
69 | Below are instructions using the `docker run` command. For an example using `docker-compose`, see the example in the [examples directory folder.](https://github.com/yesinteractive/kong-map/blob/main/examples)
70 |
71 | #### 1. Export Cluster Configurations to `KONG_CLUSTERS` Environment Variable
72 |
73 | The connections to your Kong clusters are defined via JSON. The below example illustrates adding two Kong clusters to KongMap:
74 |
75 | ```json
76 | {
77 | "my enterprise cluster": {
78 | "kong_admin_api_url": "http://kongapi_url:8001",
79 | "kong_edit_config": "true",
80 | "kong_ent": "true",
81 | "kong_ent_token": "admin",
82 | "kong_ent_token_name": "kong-admin-token",
83 | "kong_ent_manager_url": "http://kongmanager_url:8002"
84 | },
85 | "my kong open source cluster": {
86 | "kong_admin_api_url": "http://kongapi_url:8001",
87 | "kong_edit_config": "true",
88 | "kong_ent": "false",
89 | "kong_ent_token": "null",
90 | "kong_ent_token_name": "null",
91 | "kong_ent_manager_url": "null"
92 | }
93 | }
94 | ```
95 | Below is a definition of all variables in the KONG_CLUSTERS json config. All variables are required.
96 |
97 | | Parameter | Description | Required |
98 | |------------------------|-------------|-----------|
99 | | `kong_admin_api_url` | Full URL to Kong Admin API URL. Make sure there are no trailing slashes in the URL or KongMap will not work properly. Example: `http://kongadminapi:8001` | `yes` |
100 | | `kong_edit_config` | Boolean. Set to `true` to allow editing of Kong configs via KongMap. `false` will only allow readonly access to configs. | `yes` |
101 | | `kong_ent` | Boolean. Set `true` if you are connecting to a Kong Enterprise Cluster and to enable workspace support in KongMap. Only the default workspace will show if set to `false` and connected to a Kong Entperprise cluster. Otherwise set to `false` | `yes` |
102 | | `kong_ent_token` | The admin token for connecting to your Kong Enterprise Cluster Admin API. Set by RBAC configuration in Kong. Can be set to `null` if not needed. | `yes` |
103 | | `kong_ent_token_name` | The admin token header name for connecting to your Kong Enterprise Cluster Admin API. Typically is `kong-admin-token`. Can be set to `null` if not needed. | `yes` |
104 | | `kong_ent_manager_url` | Full URL to a Kong Manager if you wish to open entities in Kong Manager from KongMap. Can be set to `null` if not needed or if you do not want any Kong Manager buttons shown for the cluster. | `yes` |
105 |
106 | Export the config to a variable:
107 |
108 | ```shell
109 | export KONG_CLUSTERS='{ "my enterprise cluster": { "kong_admin_api_url": "http://kongapi_url:8001", "kong_edit_config": "true", "kong_ent": "true", "kong_ent_token": "admin", "kong_ent_token_name": "kong-admin-token", "kong_ent_manager_url": "http://kongmanager_url:8002" }}'
110 | ```
111 |
112 | #### 2. Start Container
113 |
114 | Run the container with the following command. Set the ports to your preferred exposed ports. The example below exposes KongMap on ports 8100 and 8143.
115 | Notice the `KONGMAP_URL` variable. Set this variable to the KongMap URL that you will connect to KongMap in your browser. For example, if
116 | running locally and exposing KongMap on port 8100, set to `http://localhost:8100`.
117 |
118 | ```
119 | $ docker run -d \
120 | -e "KONGMAP_CLUSTERS_JSON=$KONG_CLUSTERS" \
121 | -e "KONGMAP_URL=http://url_to_kongmap:8100" \
122 | -p 8100:8100 \
123 | -p 8143:8143 \
124 | yesinteractive/kongmap
125 | ```
126 |
127 |
128 | Full documentation available online here: [https://github.com/yesinteractive/kong-map/](https://github.com/yesinteractive/kong-map/)
129 |
130 | #### 3. Authentication
131 |
132 | If you want to enable authentication to KongMap's UI, it is recommended to run Kongmap behind your Kong Gateway and implement any authentication
133 | policies you feel is appropriate (OIDC, OAUTH2, Basic Auth, etc.) at the gateway.
134 |
135 | ## Feedback and Issues
136 |
137 | If you have questions, feedback or want to submit issues, please do so here: [https://github.com/yesinteractive/kong-map/issues](https://github.com/yesinteractive/kong-map/issues).
138 |
--------------------------------------------------------------------------------
/config/fsl_config.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
43 | # if ($stmt->execute())
44 | # {
45 | # return $stmt->fetchAll(PDO::FETCH_ASSOC);
46 | # }
47 | # return false;
48 | # }
49 | # uncomment this section below if going to use a DB using PDO
50 |
51 | /*
52 | option('db_host','localhost');
53 | option('db_name','testdb');
54 | option('db_username','root');
55 | option('db_password','test');
56 |
57 | try{
58 | $obj_db = new PDO('mysql:host='.option("db_host").';dbname='.option("db_name").';charset=utf8mb4', option("db_username"), option("db_password"));
59 | $obj_db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
60 | $GLOBALS['obj_db'] = $obj_db;
61 |
62 | }catch(PDOException $e){
63 | halt(SERVER_ERROR,"Connexion failed: ".$e); # raises an error / renders the error page and exit.
64 |
65 | }
66 |
67 | */
68 |
69 | }
70 |
71 | ?>
72 |
--------------------------------------------------------------------------------
/controllers/deck/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | - [v1.7.0](#v170---20210520)
4 | - [v1.6.0](#v160---20210408)
5 | - [v1.5.1](#v151---20210323)
6 | - [v1.5.0](#v150---20210306)
7 | - [v1.4.0](#v140---20210201)
8 | - [v1.3.0](#v130---20210115)
9 | - [v1.2.4](#v124---20210106)
10 | - [v1.2.3](#v123---20201118)
11 | - [v1.2.2](#v122---20201019)
12 | - [v1.2.1](#v121---20200804)
13 | - [v1.2.0](#v120---20200804)
14 | - [v1.1.0](#v110---20200405)
15 | - [v1.0.3](#v103---20200314)
16 | - [v1.0.2](#v102---20200221)
17 | - [v1.0.1](#v101---20200214)
18 | - [v1.0.0](#v100---20200118)
19 | - [v0.7.2](#v072---20191229)
20 | - [v0.7.1](#v071---20191224)
21 | - [v0.7.0](#v070---20191207)
22 | - [v0.6.2](#v062---20191116)
23 | - [v0.6.1](#v061---20191108)
24 | - [v0.6.0](#v060---20191103)
25 | - [v0.5.2](#v052---20190915)
26 | - [v0.5.1](#v051---20190824)
27 | - [v0.5.0](#v050---20190818)
28 | - [v0.4.0](#v040---20190610)
29 | - [v0.3.0](#v030---20190514)
30 | - [v0.2.0](#v020---20190401)
31 | - [v0.1.0](#v010---20190112)
32 |
33 | ## [v1.7.0] - 2021/05/20
34 |
35 | ### Added
36 |
37 | - State files now support environment variable-based templating. decK can
38 | substitute the value of an environment variable into an object in the state
39 | file. This is useful for avoiding persistent cleartext storage of sensitive
40 | values and populating values that vary between similar configurations.
41 | [#286](https://github.com/Kong/deck/pull/286)
42 | - Sort state file objects by name, to ease comparing state files from
43 | similarly-configured instances that do not share object IDs.
44 | [#327](https://github.com/Kong/deck/pull/327)
45 | - Added a default timeout to HTTP requests.
46 | [37eeec8](https://github.com/Kong/deck/commit/37eeec8606583d2ecfacb3265f7ff15921f0ab8d)
47 | - Implemented `convert` command for converting state files between Kong Gateway
48 | and Konnect configuration formats. This is aimed to solving migration problem between
49 | on-premise Kong clusters and Konnect SaaS.
50 | [#330](https://github.com/Kong/deck/pull/330)
51 | - Add `--konnect-addr` flag to set Konnect address. This can be used to target Konnect
52 | data-centers in geographical regions other than the US.
53 | [#374](https://github.com/Kong/deck/pull/374)
54 |
55 | ### Fixed
56 |
57 | - Fixed duplicate error message prints.
58 | [#317](https://github.com/Kong/deck/pull/317)
59 | - Handle mtls-auth credential API behavior when Kong Enterprise is running in
60 | free mode. decK no longer treats the free mode mtls-auth behavior as a fatal
61 | error.
62 | [#321](https://github.com/Kong/deck/pull/321)
63 | - `--select-tag` tags are now applied to credentials.
64 | [#282](https://github.com/Kong/deck/pull/282)
65 | - Fix empty Service Package descriptions not syncing correctly.
66 | [#347](https://github.com/Kong/deck/pull/347)
67 | - Updating certificate fields no longer deletes SNI associations.
68 | [#386](https://github.com/Kong/deck/pull/386)
69 |
70 | ### Misc
71 |
72 | - Refactored utility functionality to take advantage of new features in
73 | go-kong.
74 | - Added reworked usage analytics.
75 | [#379](https://github.com/Kong/deck/pull/379)
76 |
77 | ## [v1.6.0] - 2021/04/08
78 |
79 | ### Added
80 |
81 | - decK now prompts by default before overwriting existing state files when
82 | dumping config. Including `--yes` in args assumes yes and overwrites state
83 | files without prompting.
84 | [#285](https://github.com/Kong/deck/pull/285)
85 |
86 | ### Misc
87 |
88 | - Removed analytics.
89 | [#301](https://github.com/Kong/deck/pull/301)
90 |
91 | ### Breaking changes
92 |
93 | - Changed `github.com/blang/semver` module to `github.com/blang/semver/v4`. If
94 | you use decK's `file` package in other applications, you will also need to
95 | update the semver module used in your application.
96 | [#303](https://github.com/Kong/deck/pull/303)
97 |
98 | ## [v1.5.1] - 2021/03/23
99 |
100 | ### Fixed
101 |
102 | - Targets with identical IP and port values no longer conflict when created for
103 | different upstreams.
104 | [#280](https://github.com/Kong/deck/pull/280)
105 | - Fixed issue where Konnect flag defaults overwrote non-Konnect flag defaults,
106 | which broke the `--all-workspaces` flag.
107 | [#290](https://github.com/Kong/deck/pull/290)
108 | - Diff output no longer prints resource timestamp information.
109 | [#283](https://github.com/Kong/deck/pull/283)
110 | - Tracebacks no longer include unwanted information specific to the build
111 | environment.
112 | [#284](https://github.com/Kong/deck/pull/284)
113 |
114 | ## [v1.5.0] - 2021/03/06
115 |
116 | ### Added
117 |
118 | - decK now supports Kong Konnect. Configuration for Kong Konnect can be exported,
119 | diffed and synced using decK. A new command `konnect` has been introduced for
120 | this purpose, which has 4 sub-commands: `ping`, `dump`, `diff`, and `sync`.
121 | This feature in decK is currently in `alpha` state, which means there can be
122 | breaking changes to these commands in future releases.
123 | - decK now supports two new Kong Enterprise resources: RBAC role and RBAC
124 | endpoint-permission. Special thanks to [@tjrivera](https://github.com/tjrivera)
125 | for this contribution. A new flag `--rbac-resources-only` has been introduced
126 | to manage RBAC-only configuration via decK.
127 | [#276](https://github.com/Kong/deck/pull/276)
128 | - Certificates and Kong Services can now be managed separately. A check for
129 | existence of Certificate has been relaxed to make this possible.
130 | [#269](https://github.com/Kong/deck/pull/269)
131 |
132 | ## [v1.4.0] - 2021/02/01
133 |
134 | ### Added
135 |
136 | - deck now handles the `request_buffering` and `response_buffering` options for `Route`
137 | [#261](https://github.com/Kong/deck/pull/261)
138 |
139 | ### Fixes
140 |
141 | - Updated brew syntax
142 | [#252](https://github.com/Kong/deck/pull/252)
143 | - Fixed YAML/JSON file detection logic
144 | [#255](https://github.com/Kong/deck/pull/255)
145 |
146 | ## [v1.3.0] - 2021/01/15
147 |
148 | ### Added
149 |
150 | - decK will now retry sync operations that encounter a 500 error several times
151 | before failing completely.
152 | [#226](https://github.com/Kong/deck/pull/226)
153 |
154 | ### Fixed
155 |
156 | - Fixed regression that broke workspace creation.
157 | [#252](https://github.com/Kong/deck/pull/252)
158 | - Analytics failures no longer delay execution.
159 | [#254](https://github.com/Kong/deck/pull/254)
160 |
161 | ## [v1.2.4] - 2021/01/06
162 |
163 | ### Fixed
164 |
165 | - Fixed a bug that disabled verbose output.
166 | [#243](https://github.com/Kong/deck/pull/243)
167 | - decK no longer considers tag order significant. This avoids unnecessary
168 | resource updates for Cassandra-backed clusters.
169 | [#240](https://github.com/Kong/deck/pull/240)
170 |
171 | ## [v1.2.3] - 2020/11/18
172 |
173 | ### Fixed
174 |
175 | - Sync operations now handle plugins with array configuration correctly.
176 | [#229](https://github.com/Kong/deck/pull/229)
177 | - Removed unecessary permissions requirement for checking workspace existence.
178 | [#225](https://github.com/Kong/deck/pull/225)
179 |
180 | ## [v1.2.2] - 2020/10/19
181 |
182 | ### Added
183 |
184 | - decK now prints a change summary even if it encountered an error.
185 | [#197](https://github.com/hbagdi/deck/pull/197)
186 | - decK now prints the ID of entities that it could not successfully sync.
187 | [#199](https://github.com/hbagdi/deck/pull/199)
188 | - Issues sending analytics will now emit a panic.
189 | [#200](https://github.com/hbagdi/deck/pull/200)
190 | - decK now creates the workspace specified with `--workspace` if it is not
191 | already present.
192 | [#201](https://github.com/hbagdi/deck/pull/201)
193 | - decK prints descriptive information about duplicated entities.
194 | [#204](https://github.com/hbagdi/deck/pull/204)
195 |
196 | ### Fixed
197 |
198 | - Resolved a concurrency bug during syncs.
199 | [#202](https://github.com/hbagdi/deck/pull/202)
200 |
201 | ## [v1.2.1] - 2020/08/04
202 |
203 | ### Summary
204 |
205 | decK has move under Kong's umbrella.
206 | Due to this change, the package path has changed from `github.com/hbagdi/deck`
207 | to `github.com/kong/deck`.
208 | This release contains the updated `go.mod` over v1.2.0. There are no
209 | other changes introduced in this release.
210 |
211 | ## [v1.2.0] - 2020/08/04
212 |
213 | ### Added
214 |
215 | - decK is now compatible with Kong 2.1:
216 | - New Admin API properties for entities are added.
217 | - Ordering of operations has changed to incorporate for new foreign-relations
218 | [#192](https://github.com/hbagdi/deck/pull/192)
219 | - New flag `--db-update-propagation-delay` to add an artifical delay
220 | between Admin API calls. This is introduced for better compatibility with
221 | Cassandra backed installations of Kong.
222 | [#160](https://github.com/hbagdi/deck/pull/160)
223 | [#154](https://github.com/hbagdi/deck/pull/154)
224 | - decK now errors out if there are invalid positional arguments supplied to
225 | any command.
226 | - Stricter validation of state files.
227 | [#162](https://github.com/hbagdi/deck/pull/162)
228 | - ID property of CACertificate is always exported.
229 | [#193](https://github.com/hbagdi/deck/pull/193)
230 |
231 | ### Fixed
232 |
233 | - Ignore error for missing `.deck` config file
234 | [#168](https://github.com/hbagdi/deck/pull/168)
235 | - Correctly populate port in Service's URL (a sugar attribute)
236 | [#166](https://github.com/hbagdi/deck/pull/166)
237 | - Correct the help text for `--tls-server-name` flag
238 | [#170](https://github.com/hbagdi/deck/pull/170)
239 | - Better sanitization of `--kong-addr` input
240 | [#171](https://github.com/hbagdi/deck/pull/171)
241 | - Fix typos in the output of `--help`
242 | [#174](https://github.com/hbagdi/deck/pull/174)
243 | - Improve language of warning message for basic-auth credentials
244 | [#145](https://github.com/hbagdi/deck/pull/145)
245 | - Deduplicate `select_tags` input
246 | [#183](https://github.com/hbagdi/deck/pull/183)
247 |
248 |
249 | ### Enterprise-only
250 |
251 | - Added support for managing `mtls-auth` credentials.
252 | [#175](https://github.com/hbagdi/deck/pull/175)
253 | - decK now automatically creates a workspace if one does not already exist
254 | during a `sync` operation.
255 | [#187](https://github.com/hbagdi/deck/pull/187)
256 | - Added `--workspace` flag to `ping` command. This can be used to verify
257 | connectivity with Kong Enterprise when running as an RBAC role with lower
258 | priviliges.
259 | - New `--workspace` flag for `diff` and `sync` command to provide workspace
260 | via the CLI instead of state file. Workspace defined in state file will be
261 | overriden if this flag is provided.
262 | - New `--skip-workspace-crud` flag to skip any workspace related operations.
263 | This flag can be used when running as as an RBAC role with lower priviliges.
264 | The content can be synced to specific workspaces but decK will not attempt
265 | to create or verify existence of a workspace.
266 | [#157](https://github.com/hbagdi/deck/pull/157)
267 | - Additional checks for existence of workspace before performing dump or reset
268 | [#167](https://github.com/hbagdi/deck/pull/167)
269 | - Improve end-user error message when workspace doesn't exist
270 |
271 | #### Misc
272 |
273 | - CI changed from Travis to Github Actions
274 | - Improved code quality with addition of golangci-lint
275 | - Default branch for the project has been changed from `master` to `main`
276 |
277 | ## [v1.1.0] - 2020/04/05
278 |
279 | ### Added
280 |
281 | - Added support for multiple files or directories to `-s/--state`
282 | flag. Use `-s` multiple times or specify multiple files/directories using
283 | a comma separated list.
284 | [#137](https://github.com/hbagdi/deck/pull/137)
285 | - **Performance**
286 | decK should be much faster than before. Requests to Kong are
287 | now concurrent. `dump`, `sync`, `diff` and `reset`
288 | commands will be faster than before, by at least 2x.
289 | - SNI entity in Kong is not supported natively supported
290 | [#139](https://github.com/hbagdi/deck/pull/139). Most users will not observe
291 | any changes. `id` and `tags` are now supported for the SNI entity in Kong.
292 |
293 | ### Under the hood
294 |
295 | - Go has been upgraded to 1.14.1
296 | - Alpine base image for Docker has been upgraded to 3.11
297 | - Multiple other dependencies have also been upgraded, but these have no
298 | user-visible changes.
299 |
300 | ### Fixed
301 |
302 | - Default values for `retries` in Service entity and
303 | `HTTPSVerifyCertificate` in Upstream entity have been removed.
304 | These values can be set to `0` and `false` respectively now.
305 | [#134](https://github.com/hbagdi/deck/issues/134)
306 |
307 | ## [v1.0.3] - 2020/03/14
308 |
309 | ### Fixed
310 |
311 | - Fix certificate diff for certificates with no associated snis
312 | [#131](https://github.com/hbagdi/deck/issues/131)
313 |
314 | ## [v1.0.2] - 2020/02/21
315 |
316 | ### Fixed
317 |
318 | - Fix broken `ca_certificate` entity support
319 | [#127](https://github.com/hbagdi/deck/pull/127)
320 |
321 | ## [v1.0.1] - 2020/02/14
322 |
323 | ### Added
324 |
325 | - decK now supports the `url` sugar property on Service entity.
326 | [#123](https://github.com/hbagdi/deck/issues/123)
327 |
328 | ## [v1.0.0] - 2020/01/18
329 |
330 | ### Fixed
331 |
332 | - decK doesn't error out if bundled plugins in Kong are disabled
333 | [#121](https://github.com/hbagdi/deck/pull/121)
334 | - Consumer-specific plugins are excluded when `--skip-consumers` is used
335 | [#119](https://github.com/hbagdi/deck/issues/119)
336 |
337 | ### Internal
338 |
339 | - `go-kong` has been upgraded to v0.11.0, which brings in support for
340 | Kong 2.0.
341 | - All other dependencies have also been upgraded, but these have no
342 | user-visible changes.
343 | [b603f9](https://github.com/hbagdi/deck/commit/b603f9)
344 |
345 | ## [v0.7.2] - 2019/12/29
346 |
347 | ### Fixed
348 |
349 | - Kong's version is correctly parsed; v0.7.1 is unusable because
350 | of this bug.
351 | [#117](https://github.com/hbagdi/deck/issues/117)
352 |
353 | ## [v0.7.1] - 2019/12/24
354 |
355 | ### Fixed
356 |
357 | - Backward compatibility for credentials; tags are no longer injected into
358 | credentials for Kong versions below 1.4
359 | [#114](https://github.com/hbagdi/deck/issues/114)
360 |
361 | ## [v0.7.0] - 2019/12/07
362 |
363 | ### Breaking changes
364 |
365 | - `sync` command now shows the progress of the sync. Previously, the command
366 | did not output anything but errors.
367 |
368 | ### Added
369 |
370 | - Configuration of multiple plugin instances can now be de-duplicated using
371 | `_plugin_configs` field in the state file.
372 | [#93](https://github.com/hbagdi/deck/issues/93)
373 | - A summary is now presented at the end of a `diff` or `sync`
374 | operation showing the count of resources created/updated/deleted.
375 | [#101](https://github.com/hbagdi/deck/issues/101)
376 | - `sync` command now shows the progress of the sync as the sync takes place,
377 | making it easier to track progress in large environments.
378 | [#100](https://github.com/hbagdi/deck/issues/100)
379 | - `--non-zero-exit-code` flag hsa been added to `diff` command. Using
380 | this flag causes decK to exit with a non-zero exit code if a diff is
381 | detected, making it easier to script decK in CI pipelines.
382 | [#98](https://github.com/hbagdi/deck/issues/98)
383 | - A new docs website has been setup for the project:
384 | [https://deck.yolo42.com](https://deck.yolo42.com)
385 |
386 | ## [v0.6.2] - 2019/11/16
387 |
388 | ### Fixed
389 |
390 | - Service-less routes are correctly processed
391 | [#103](https://github.com/hbagdi/deck/issues/103)
392 | - Plugins for routes are correctly processed
393 | [#104](https://github.com/hbagdi/deck/issues/104)
394 |
395 | ## [v0.6.1] - 2019/11/08
396 |
397 | ### Fixed
398 |
399 | - Check for workspace makes call the right endpoint
400 | [#94](https://github.com/hbagdi/deck/issues/94)
401 | - Error checking is performed correctly when ensuring existence of a workspace
402 | [#95](https://github.com/hbagdi/deck/issues/95)
403 | - Multiple upstream definitions are read correctly and synced up
404 | [#96](https://github.com/hbagdi/deck/issues/96)
405 |
406 | ## [v0.6.0] - 2019/11/03
407 |
408 | ### Breaking changes
409 |
410 | - `ID` field is required for `Certificate` entity. Previous state files will
411 | break if `ID` is not present on this entity. You can use `dump` command
412 | to generate new state files which includes the `ID` field.
413 | - SNIs are exported under the `name` key under Certificate entity to match
414 | Kong's declarative configuration format.
415 |
416 | ### Added
417 |
418 | - Kong's configuration can now be synced/diffed/dumped using JSON format,
419 | in addition to the existing YAML format. Use the `--format` flag to specify
420 | the format.
421 | [#35](https://github.com/hbagdi/deck/issues/35)
422 | - Plugins associated with multiple entities e.g. a plugin for a combination of
423 | route and a consumer in Kong are now supported.
424 | [#13](https://github.com/hbagdi/deck/issues/13)
425 | - JSON-schema based validation is now performed on the input file(s) for every
426 | command.
427 | - New `validate` command has been added to validate an existing state file.
428 | This performs a JSON-schema based sanity check on the file along-with foreign
429 | reference checks to check for dangling pointers.
430 | - Service-less routes are now supported by decK.
431 | - `name` is no longer a required field for routes and services entities
432 | in Kong. If a `name` is not present, decK exports the entity with it's `ID`.
433 | - Client-certificates on Service entity are now a supported.
434 | - Credential entities like key-auth, basic-auth now support tagging.
435 | - `--parallelism` flag has been added to `sync` and `diff` commands to control
436 | the number of concurrenty request to Kong's Admin API.
437 | [#85](https://github.com/hbagdi/deck/issues/85)
438 | - `diff` and `sync` show a descriptive error when a workspace doesn't exist
439 | for Kong Enterprise.
440 | [102ed5dd](https://github.com/hbagdi/deck/commit/102ed5dd6f8ef)
441 | - `--select-tag` flag has been added to `diff` and `sync` command for use-cases
442 | where the tags are not part of the state file. It is not recommended to
443 | use these flags unless you know what you are doing.
444 | [#81](https://github.com/hbagdi/deck/issues/81)
445 | - ID for any entity can now be specified. decK previously ignored the ID for
446 | any entity if one was specified. Entities can also be exported with the `ID`
447 | field set using `--with-id` flag on the `dump` command.
448 | [#29](https://github.com/hbagdi/deck/issues/29)
449 |
450 | ### Fixed
451 |
452 | - decK runs as non-root user in the Docker image.
453 | [#82](https://github.com/hbagdi/deck/issues/82)
454 | - SNIs are now exported same as Kong's format i.e. they are exported under a
455 | `name` key under the certificates entity.
456 | [#76](https://github.com/hbagdi/deck/issues/76)
457 | - Errors are made more descriptive in few commands.
458 | - decK's binary inside the Docker image now contains versioning information.
459 | [#38](https://github.com/hbagdi/deck/issues/38)
460 |
461 |
462 | ### Internal
463 |
464 | - Go has been bumped up to `1.13.4`.
465 | - `go-kong` has been bumped up to `v0.10.0`.
466 | - Reduced memory allocation, which should result in less GC pressure.
467 |
468 | ## [v0.5.2] - 2019/09/15
469 |
470 | ### Added
471 |
472 | - `-w/--workspace` flag has been added to the `reset` command to reset a
473 | specific workspace in Kong Enterprise.
474 | [#74](https://github.com/hbagdi/deck/issues/74)
475 | - `--all-workspaces` flag has been added to the `reset` command to reset
476 | all workspaces in Kong Enterprise.
477 | [#74](https://github.com/hbagdi/deck/issues/74)
478 | - A warning is logged when basic-auth credentials are being synced.
479 | [#49](https://github.com/hbagdi/deck/issues/49)
480 |
481 | ### Fixed
482 |
483 | - Kong Enterprise Developer Portal exposes the credentials (basic/key) of
484 | Developers on the Admin API, but doesn't expose the consumers causing
485 | issues during export. decK now ignores these credentials in Kong Enterprise.
486 | [#75](https://github.com/hbagdi/deck/issues/75)
487 |
488 | ### Internal
489 |
490 | - Go version has been bumped to 1.13.
491 |
492 | ## [v0.5.1] - 2019/08/24
493 |
494 | ### Added
495 |
496 | - `oauth2` credentials associated with consumers are now supported.
497 | [#67](https://github.com/hbagdi/deck/pull/67)
498 |
499 | ### Fixed
500 |
501 | - The same target can be associated with multiple upstreams.
502 | [#57](https://github.com/hbagdi/deck/issues/57)
503 | - Fix compatibility with Kong < 1.3.
504 | [#59](https://github.com/hbagdi/deck/issues/59)
505 | - Ignore credentials for consumers which are not in the sub-set of
506 | the configuration being synced.
507 | [#65](https://github.com/hbagdi/deck/issues/65)
508 |
509 | ## [v0.5.0] - 2019/08/18
510 |
511 | ### Summary
512 |
513 | This release brings the following features:
514 | - Consumer credentials are now supported
515 | - Support for Kong 1.3
516 | - Kong Enterprise workspace support
517 | - Reading configuration from multiple files in a directories
518 |
519 | ### Breaking changes
520 |
521 | No breaking changes have been introduced in this release.
522 |
523 | ### Added
524 |
525 | - **Consumer credentials**
526 | The following entities associate with a consumer in Kong are now supported [#12](https://github.com/hbagdi/deck/issues/12):
527 | - `key-auth`
528 | - `basic-auth`
529 | - `hmac-auth`
530 | - `jwt`
531 | - `acl`
532 |
533 | - decK's exported YAML is now compatible with Kong's declarative config
534 | file.
535 | - **Homebrew support**
536 | decK can now be installed using Homebrew on macOS:
537 | ```
538 | brew tap hbagdi/deck
539 | brew install deck
540 | ```
541 | - **Multiple state files**
542 | decK can now read the configuration of Kong from multiple YAML files in a directory. You can split your configuration
543 | into files in any way you would like.
544 | [#22](https://github.com/hbagdi/deck/issues/22)
545 | - Upcoming Kong 1.3 is now supported.
546 | [#36](https://github.com/hbagdi/deck/issues/36)
547 | - **Kong Enterprise only features:**
548 | Workspaces are now natively supported in decK
549 | - `-w/--workspace` flag can be specified in the `dump` command to
550 | export configuration of a single workspace.
551 | - `--all-workspaces` flag in `dump` command will export all workspaces
552 | in Kong Enteprise. Each workspace lives in a separate state file.
553 | - `diff` and `sync` command now support workspaces via the `_workspace`
554 | attribute in the state file.
555 |
556 | ### Fixed
557 |
558 | - decK now supports TCP services in Kong.
559 | [#44](https://github.com/hbagdi/deck/issues/44)
560 | - Add missing `interval` field in Upstream entity's
561 | unhealthy active healthchecks
562 | [#45](https://github.com/hbagdi/deck/pull/45)
563 | - Docker image now contains only the binary and not the entire source code.
564 | [#34](https://github.com/hbagdi/deck/pull/34)
565 | Thanks to [David Cruz](https://github.com/davidcv5) for the contribution.
566 |
567 | ## [v0.4.0] - 2019/06/10
568 |
569 | ### Summary
570 |
571 | This release introduces support for Kong 1.2.x.
572 |
573 | ### Breaking changes
574 |
575 | - `strip_path` attribute of Route can now be set to false. The default value
576 | is now false, which was true previously.
577 | [#18](https://github.com/hbagdi/deck/issues/18)
578 |
579 | ### Added
580 |
581 | - `https_redirect_status_code` attribute of Route in Kong can be set,
582 | and defaults to `426`.
583 |
584 | ## [v0.3.0] - 2019/05/14
585 |
586 | ### Breaking changes
587 |
588 | No breaking changes have been introduced in this release.
589 |
590 | ### Added
591 |
592 | - **Tag-based distributed configuration management**
593 | Only a subset of Kong entities sharing a (set of) tag can now be exported,
594 | deleted, diffed or synced.
595 | decK can now manage your Kong's configuration in a distributed manner,
596 | whereby you can split Kong's configuration by team and each team can manage
597 | it's own configuration. Use `select-tag` feature in all the commands and
598 | config file for this purpose.
599 | [#17](https://github.com/hbagdi/deck/pull/17)
600 | - **Read/write state from stdout/stdin**
601 | Config file can now be read in from standard-input and written out to
602 | standard-output.
603 | [#10](https://github.com/hbagdi/deck/pull/10),
604 | [#11](https://github.com/hbagdi/deck/pull/11)
605 | Thanks to [@matthewbednarski](https://github.com/matthewbednarski) for the contribution.
606 | - **Automated defaults**
607 | No need to specify default values for all core Kong entities,
608 | further simplifying your Kong's configuration.
609 | Default values for plugin configuration still need to be defined, this is on
610 | the roadmap.
611 | [b448d4f](https://github.com/hbagdi/deck/commit/b448d4f)
612 | - Add support for new properties in Upstream entity in Kong.
613 | [080200d](https://github.com/hbagdi/deck/commit/080200d)
614 | - Empty plugins and other Kong entities are not populated in the config file
615 | as empty arrays to keep the file concise and clean.
616 | [ae38f1b](https://github.com/hbagdi/deck/commit/ae38f1b)
617 | - Docker image is now available via Docker Hub.
618 | You can use `docker pull hbagdi/deck` to pull down decK in a Docker image.
619 |
620 | ### Fixed
621 |
622 | - Empty arrays in plugin configs are not treated as nil anymore.
623 | [#9](https://github.com/hbagdi/deck/pull/9)
624 | - Correctly sync plugins which are out of sync. Protocols field
625 | in plugins can be confused with protocols field in routes in Kong
626 | [#6](https://github.com/hbagdi/deck/pull/6)
627 | Thanks to [@davidcv5](https://github.com/davidcv5) for the contribution.
628 | - Throw an error if an object is not marshalled into YAML correctly.
629 | - Correctly create service-level plugins for Kong >= 1.1
630 | [#16](https://github.com/hbagdi/deck/pull/16)
631 |
632 | ### Misc
633 |
634 | - `go-kong` has been bumped up to v0.4.1.
635 |
636 | ## [v0.2.0] - 2019/04/01
637 |
638 | ### Breaking changes
639 |
640 | No breaking changes have been introduced in this release.
641 |
642 | ### Added
643 |
644 | - **Consumers and consumer-level plugins** can now be exported from Kong and
645 | synced to Kong.
646 | - `--skip-consumers` flag has been introduced to various sub-commands to skip
647 | management of consumers in environments where they are created dynamically.`
648 | - **Authentication support**: custom HTTP Headers (key:value) can be injected
649 | into requests that decK makes to Kong's Admin API using the `--headers`
650 | CLI flag.
651 | [#1](https://github.com/hbagdi/deck/pull/1)
652 | Thanks to [@davidcv5](https://github.com/davidcv5) for the contribution.
653 |
654 | ### Fixed
655 |
656 | - Infinite loop in pagination for exporting entities in Kong
657 | [#2](https://github.com/hbagdi/deck/pull/2)
658 | Thanks to [@lmika](https://github.com/lmika) for the contribution.
659 | - Plugins are updated using PUT requests instead of PATCH to
660 | avoid any schema violations.
661 |
662 | ## [v0.1.0] - 2019/01/12
663 |
664 | ### Summary
665 |
666 | Debut release of decK
667 |
668 | [v1.7.0]: https://github.com/kong/deck/compare/v1.6.0...v1.7.0
669 | [v1.6.0]: https://github.com/kong/deck/compare/v1.5.1...v1.6.0
670 | [v1.5.1]: https://github.com/kong/deck/compare/v1.5.0...v1.5.1
671 | [v1.5.0]: https://github.com/kong/deck/compare/v1.4.0...v1.5.0
672 | [v1.4.0]: https://github.com/kong/deck/compare/v1.3.0...v1.4.0
673 | [v1.3.0]: https://github.com/kong/deck/compare/v1.2.4...v1.3.0
674 | [v1.2.4]: https://github.com/kong/deck/compare/v1.2.3...v1.2.4
675 | [v1.2.3]: https://github.com/kong/deck/compare/v1.2.2...v1.2.3
676 | [v1.2.2]: https://github.com/kong/deck/compare/v1.2.1...v1.2.2
677 | [v1.2.1]: https://github.com/hbagdi/deck/compare/v1.2.0...v1.2.1
678 | [v1.2.0]: https://github.com/hbagdi/deck/compare/v1.1.0...v1.2.0
679 | [v1.1.0]: https://github.com/hbagdi/deck/compare/v1.0.3...v1.1.0
680 | [v1.0.3]: https://github.com/hbagdi/deck/compare/v1.0.2...v1.0.3
681 | [v1.0.2]: https://github.com/hbagdi/deck/compare/v1.0.1...v1.0.2
682 | [v1.0.1]: https://github.com/hbagdi/deck/compare/v1.0.0...v1.0.1
683 | [v1.0.0]: https://github.com/hbagdi/deck/compare/v0.7.2...v1.0.0
684 | [v0.7.2]: https://github.com/hbagdi/deck/compare/v0.7.1...v0.7.2
685 | [v0.7.1]: https://github.com/hbagdi/deck/compare/v0.7.0...v0.7.1
686 | [v0.7.0]: https://github.com/hbagdi/deck/compare/v0.6.2...v0.7.0
687 | [v0.6.2]: https://github.com/hbagdi/deck/compare/v0.6.1...v0.6.2
688 | [v0.6.1]: https://github.com/hbagdi/deck/compare/v0.6.0...v0.6.1
689 | [v0.6.0]: https://github.com/hbagdi/deck/compare/v0.5.2...v0.6.0
690 | [v0.5.2]: https://github.com/hbagdi/deck/compare/v0.5.1...v0.5.2
691 | [v0.5.1]: https://github.com/hbagdi/deck/compare/v0.5.0...v0.5.1
692 | [v0.5.0]: https://github.com/hbagdi/deck/compare/v0.4.0...v0.5.0
693 | [v0.4.0]: https://github.com/hbagdi/deck/compare/v0.3.0...v0.4.0
694 | [v0.3.0]: https://github.com/hbagdi/deck/compare/v0.2.0...v0.3.0
695 | [v0.2.0]: https://github.com/hbagdi/deck/compare/v0.1.0...v0.2.0
696 | [v0.1.0]: https://github.com/hbagdi/deck/compare/0c7e839...v0.1.0
697 |
--------------------------------------------------------------------------------
/controllers/deck/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2018-2020 Harry Bagdi
191 | Copyright 2020-2020 Kong Inc.
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
--------------------------------------------------------------------------------
/controllers/deck/README.md:
--------------------------------------------------------------------------------
1 | # decK: Declarative configuration for Kong
2 |
3 | decK provides declarative configuration and drift detection for Kong.
4 |
5 | [](https://github.com/kong/deck/actions?query=branch%3Amain+event%3Apush)
6 | [](https://codecov.io/gh/Kong/deck)
7 | [](https://goreportcard.com/report/github.com/kong/deck)
8 |
9 | [](https://asciinema.org/a/238318)
10 |
11 | ## Table of Content
12 |
13 | - [**Features**](#features)
14 | - [**Compatibility**](#compatibility)
15 | - [**Installation**](#installation)
16 | - [**Documentation**](#documentation)
17 | - [**Stale issue and pull request policy**](#stale-issue-and-pull-request-policy)
18 | - [**License**](#license)
19 |
20 | ## Features
21 |
22 | - **Export**
23 | Existing Kong configuration to a YAML configuration file
24 | This can be used to backup Kong's configuration.
25 | - **Import**
26 | Kong's database can be populated using the exported or a hand written config
27 | file.
28 | - **Diff and sync capabilities**
29 | decK can diff the configuration in the config file and
30 | the configuration in Kong's DB and then sync it as well.
31 | This can be used to detect config drifts or manual interventions.
32 | - **Reverse sync**
33 | decK supports a sync the other way as well, meaning if an
34 | entity is created in Kong and doesn't add it to the config file,
35 | decK will detect the change.
36 | - **Validation**
37 | decK can validate a YAML file that you backup or modify to catch errors
38 | early on.
39 | - **Reset**
40 | This can be used to drops all entities in Kong's DB.
41 | - **Parallel operations**
42 | All Admin API calls to Kong are executed in parallel using multiple
43 | threads to speed up the sync process.
44 | - **Authentication with Kong**
45 | Custom HTTP headers can be injected in requests to Kong's Admin API
46 | for authentication/authorization purposes.
47 | - **Manage Kong's config with multiple config file**
48 | Split your Kong's configuration into multiple logical files based on a shared
49 | set of tags amongst entities.
50 | - **Designed to automate configuration management**
51 | decK is designed to be part of your CI pipeline and can be used to not only
52 | push configuration to Kong but also detect drifts in configuration.
53 |
54 | ## Compatibility
55 |
56 | decK is compatible with Kong Gateway >= 1.x and Kong Enterprise >= 0.35.
57 |
58 | ## Installation
59 |
60 | ### macOS
61 |
62 | If you are on macOS, install decK using brew:
63 |
64 | ```shell
65 | $ brew tap kong/deck
66 | $ brew install deck
67 | ```
68 |
69 | ### Linux
70 |
71 | If you are Linux, you can either use the Debian or RPM archive from
72 | the Github [release page](https://github.com/kong/deck/releases)
73 | or install by downloading the binary:
74 |
75 | ```shel
76 | $ curl -sL https://github.com/kong/deck/releases/download/v1.2.0/deck_1.2.0_linux_amd64.tar.gz -o deck.tar.gz
77 | $ tar -xf deck.tar.gz -C /tmp
78 | $ sudo cp /tmp/deck /usr/local/bin/
79 | ```
80 |
81 | ### Docker image
82 |
83 | Docker image is hosted on [Docker Hub](https://hub.docker.com/r/kong/deck).
84 |
85 | You can get the image with the command:
86 |
87 | ```
88 | docker pull kong/deck
89 | ```
90 |
91 | ## Documentation
92 |
93 | You can use `--help` flag once you've decK installed on your system
94 | to get help in the terminal itself.
95 |
96 | The project's documentation is hosted at
97 | [https://docs.konghq.com/deck/overview](https://docs.konghq.com/deck/overview).
98 |
99 | ## Changelog
100 |
101 | Changelog can be found in the [CHANGELOG.md](CHANGELOG.md) file.
102 |
103 | ## Stale issue and pull request policy
104 |
105 | To ensure our backlog is organized and up to date, we will close issues and
106 | pull requests that have been inactive awaiting a community response for over 2
107 | weeks. If you wish to reopen a closed issue or PR to continue work, please
108 | leave a comment asking a team member to do so.
109 |
110 | ## License
111 |
112 | decK is licensed with Apache License Version 2.0.
113 | Please read the [LICENSE](LICENSE) file for more details.
114 |
--------------------------------------------------------------------------------
/controllers/deck/deck:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/controllers/deck/deck
--------------------------------------------------------------------------------
/controllers/deck/kong.yaml:
--------------------------------------------------------------------------------
1 | Emptied
--------------------------------------------------------------------------------
/examples/dadjokes.yaml:
--------------------------------------------------------------------------------
1 | # Example declarative configuration for Kong API Gateway.
2 | # Will create /jokes endpoint with a rate limit of 5
3 | # requests per minute. Dadjokes.online is being used
4 | # as the upstream searvice.
5 | _format_version: "1.1"
6 | services:
7 | - connect_timeout: 60000
8 | host: dadjokes.online
9 | name: dad_jokes
10 | path: /echo
11 | port: 80
12 | protocol: http
13 | read_timeout: 60000
14 | retries: 5
15 | write_timeout: 60000
16 | routes:
17 | - name: dad_jokes
18 | paths:
19 | - /jokes
20 | path_handling: v1
21 | preserve_host: false
22 | protocols:
23 | - http
24 | regex_priority: 0
25 | strip_path: true
26 | https_redirect_status_code: 426
27 | plugins:
28 | - name: rate-limiting
29 | config:
30 | day: null
31 | fault_tolerant: true
32 | header_name: null
33 | hide_client_headers: false
34 | hour: null
35 | limit_by: consumer
36 | minute: 5
37 | month: null
38 | policy: cluster
39 | redis_database: 0
40 | redis_host: null
41 | redis_password: null
42 | redis_port: 6379
43 | redis_timeout: 2000
44 | second: null
45 | year: null
46 | enabled: true
47 | protocols:
48 | - grpc
49 | - grpcs
50 | - http
51 | - https
--------------------------------------------------------------------------------
/examples/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | # docker compose example
2 | # exposes kongmap on port 8100
3 | # must set KONGMAP_CLUSTERS_JSON either in file or as a variable with export command prior
4 | # usage example: docker-compose -f docker-compose.yaml up -d
5 | ---
6 | version: '3'
7 | services:
8 | kongmap:
9 | image: docker.io/yesinteractive/kongmap
10 | container_name: kongmap
11 | environment:
12 | - KONGMAP_CLUSTERS_JSON=$KONG_CLUSTERS
13 | - KONGMAP_URL=http://url_to_kongmap:8100
14 | restart: always
15 | ports:
16 | - "8100:80"
17 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | \n";
70 | $output .= "";
73 |
74 | */
75 |
76 | return $output;
77 | }
78 |
79 |
80 | run();
81 |
82 | ##############################################################################
83 | # Data Models
84 | ##############################################################################
85 | #
86 |
87 | ##############################################################################
88 | # layouts (views) and html templates
89 | ##############################################################################
90 | # Layouts are autoloaded from views directory or can be referended
91 | # as a function like below.
92 |
93 | function html_my_layout($vars){ extract($vars);?>
94 |
95 |
96 |
97 |
98 | Hello world!
99 |
100 |
101 |
102 |
105 | Hello !
106 | How are you ?
107 |
108 |
109 | ?>)
110 | 
Your request for " . $errstr . " came up ghosts." ;
120 | return html($code);
121 | }
122 |
123 |
124 |
125 | ?>
126 |
--------------------------------------------------------------------------------
/lib/3rd_party_helpers/Medoo.php:
--------------------------------------------------------------------------------
1 | type = strtolower($options[ 'database_type' ]);
50 |
51 | if ($this->type === 'mariadb')
52 | {
53 | $this->type = 'mysql';
54 | }
55 | }
56 |
57 | if (isset($options[ 'prefix' ]))
58 | {
59 | $this->prefix = $options[ 'prefix' ];
60 | }
61 |
62 | if (isset($options[ 'logging' ]) && is_bool($options[ 'logging' ]))
63 | {
64 | $this->logging = $options[ 'logging' ];
65 | }
66 |
67 | $option = isset($options[ 'option' ]) ? $options[ 'option' ] : [];
68 | $commands = (isset($options[ 'command' ]) && is_array($options[ 'command' ])) ? $options[ 'command' ] : [];
69 |
70 | switch ($this->type)
71 | {
72 | case 'mysql':
73 | // Make MySQL using standard quoted identifier
74 | $commands[] = 'SET SQL_MODE=ANSI_QUOTES';
75 |
76 | break;
77 |
78 | case 'mssql':
79 | // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting
80 | $commands[] = 'SET QUOTED_IDENTIFIER ON';
81 |
82 | // Make ANSI_NULLS is ON for NULL value
83 | $commands[] = 'SET ANSI_NULLS ON';
84 |
85 | break;
86 | }
87 |
88 | if (isset($options[ 'pdo' ]))
89 | {
90 | if (!$options[ 'pdo' ] instanceof PDO)
91 | {
92 | throw new InvalidArgumentException('Invalid PDO object supplied');
93 | }
94 |
95 | $this->pdo = $options[ 'pdo' ];
96 |
97 | foreach ($commands as $value)
98 | {
99 | $this->pdo->exec($value);
100 | }
101 |
102 | return;
103 | }
104 |
105 | if (isset($options[ 'dsn' ]))
106 | {
107 | if (is_array($options[ 'dsn' ]) && isset($options[ 'dsn' ][ 'driver' ]))
108 | {
109 | $attr = $options[ 'dsn' ];
110 | }
111 | else
112 | {
113 | throw new InvalidArgumentException('Invalid DSN option supplied');
114 | }
115 | }
116 | else
117 | {
118 | if (
119 | isset($options[ 'port' ]) &&
120 | is_int($options[ 'port' ] * 1)
121 | )
122 | {
123 | $port = $options[ 'port' ];
124 | }
125 |
126 | $is_port = isset($port);
127 |
128 | switch ($this->type)
129 | {
130 | case 'mysql':
131 | $attr = [
132 | 'driver' => 'mysql',
133 | 'dbname' => $options[ 'database_name' ]
134 | ];
135 |
136 | if (isset($options[ 'socket' ]))
137 | {
138 | $attr[ 'unix_socket' ] = $options[ 'socket' ];
139 | }
140 | else
141 | {
142 | $attr[ 'host' ] = $options[ 'server' ];
143 |
144 | if ($is_port)
145 | {
146 | $attr[ 'port' ] = $port;
147 | }
148 | }
149 |
150 | break;
151 |
152 | case 'pgsql':
153 | $attr = [
154 | 'driver' => 'pgsql',
155 | 'host' => $options[ 'server' ],
156 | 'dbname' => $options[ 'database_name' ]
157 | ];
158 |
159 | if ($is_port)
160 | {
161 | $attr[ 'port' ] = $port;
162 | }
163 |
164 | break;
165 |
166 | case 'sybase':
167 | $attr = [
168 | 'driver' => 'dblib',
169 | 'host' => $options[ 'server' ],
170 | 'dbname' => $options[ 'database_name' ]
171 | ];
172 |
173 | if ($is_port)
174 | {
175 | $attr[ 'port' ] = $port;
176 | }
177 |
178 | break;
179 |
180 | case 'oracle':
181 | $attr = [
182 | 'driver' => 'oci',
183 | 'dbname' => $options[ 'server' ] ?
184 | '//' . $options[ 'server' ] . ($is_port ? ':' . $port : ':1521') . '/' . $options[ 'database_name' ] :
185 | $options[ 'database_name' ]
186 | ];
187 |
188 | if (isset($options[ 'charset' ]))
189 | {
190 | $attr[ 'charset' ] = $options[ 'charset' ];
191 | }
192 |
193 | break;
194 |
195 | case 'mssql':
196 | if (isset($options[ 'driver' ]) && $options[ 'driver' ] === 'dblib')
197 | {
198 | $attr = [
199 | 'driver' => 'dblib',
200 | 'host' => $options[ 'server' ] . ($is_port ? ':' . $port : ''),
201 | 'dbname' => $options[ 'database_name' ]
202 | ];
203 |
204 | if (isset($options[ 'appname' ]))
205 | {
206 | $attr[ 'appname' ] = $options[ 'appname' ];
207 | }
208 |
209 | if (isset($options[ 'charset' ]))
210 | {
211 | $attr[ 'charset' ] = $options[ 'charset' ];
212 | }
213 | }
214 | else
215 | {
216 | $attr = [
217 | 'driver' => 'sqlsrv',
218 | 'Server' => $options[ 'server' ] . ($is_port ? ',' . $port : ''),
219 | 'Database' => $options[ 'database_name' ]
220 | ];
221 |
222 | if (isset($options[ 'appname' ]))
223 | {
224 | $attr[ 'APP' ] = $options[ 'appname' ];
225 | }
226 |
227 | $config = [
228 | 'ApplicationIntent',
229 | 'AttachDBFileName',
230 | 'Authentication',
231 | 'ColumnEncryption',
232 | 'ConnectionPooling',
233 | 'Encrypt',
234 | 'Failover_Partner',
235 | 'KeyStoreAuthentication',
236 | 'KeyStorePrincipalId',
237 | 'KeyStoreSecret',
238 | 'LoginTimeout',
239 | 'MultipleActiveResultSets',
240 | 'MultiSubnetFailover',
241 | 'Scrollable',
242 | 'TraceFile',
243 | 'TraceOn',
244 | 'TransactionIsolation',
245 | 'TransparentNetworkIPResolution',
246 | 'TrustServerCertificate',
247 | 'WSID',
248 | ];
249 |
250 | foreach ($config as $value)
251 | {
252 | $keyname = strtolower(preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $value));
253 |
254 | if (isset($options[ $keyname ]))
255 | {
256 | $attr[ $value ] = $options[ $keyname ];
257 | }
258 | }
259 | }
260 |
261 | break;
262 |
263 | case 'sqlite':
264 | $attr = [
265 | 'driver' => 'sqlite',
266 | $options[ 'database_file' ]
267 | ];
268 |
269 | break;
270 | }
271 | }
272 |
273 | if (!isset($attr))
274 | {
275 | throw new InvalidArgumentException('Incorrect connection options');
276 | }
277 |
278 | $driver = $attr[ 'driver' ];
279 |
280 | if (!in_array($driver, PDO::getAvailableDrivers()))
281 | {
282 | throw new InvalidArgumentException("Unsupported PDO driver: {$driver}");
283 | }
284 |
285 | unset($attr[ 'driver' ]);
286 |
287 | $stack = [];
288 |
289 | foreach ($attr as $key => $value)
290 | {
291 | $stack[] = is_int($key) ? $value : $key . '=' . $value;
292 | }
293 |
294 | $dsn = $driver . ':' . implode(';', $stack);
295 |
296 | if (
297 | in_array($this->type, ['mysql', 'pgsql', 'sybase', 'mssql']) &&
298 | isset($options[ 'charset' ])
299 | )
300 | {
301 | $commands[] = "SET NAMES '{$options[ 'charset' ]}'" . (
302 | $this->type === 'mysql' && isset($options[ 'collation' ]) ?
303 | " COLLATE '{$options[ 'collation' ]}'" : ''
304 | );
305 | }
306 |
307 | $this->dsn = $dsn;
308 |
309 | try {
310 | $this->pdo = new PDO(
311 | $dsn,
312 | isset($options[ 'username' ]) ? $options[ 'username' ] : null,
313 | isset($options[ 'password' ]) ? $options[ 'password' ] : null,
314 | $option
315 | );
316 |
317 | foreach ($commands as $value)
318 | {
319 | $this->pdo->exec($value);
320 | }
321 | }
322 | catch (PDOException $e) {
323 | throw new PDOException($e->getMessage());
324 | }
325 | }
326 |
327 | public function query($query, $map = [])
328 | {
329 | $raw = $this->raw($query, $map);
330 |
331 | $query = $this->buildRaw($raw, $map);
332 |
333 | return $this->exec($query, $map);
334 | }
335 |
336 | public function exec($query, $map = [])
337 | {
338 | $this->statement = null;
339 |
340 | if ($this->debug_mode)
341 | {
342 | echo $this->generate($query, $map);
343 |
344 | $this->debug_mode = false;
345 |
346 | return false;
347 | }
348 |
349 | if ($this->logging)
350 | {
351 | $this->logs[] = [$query, $map];
352 | }
353 | else
354 | {
355 | $this->logs = [[$query, $map]];
356 | }
357 |
358 | $statement = $this->pdo->prepare($query);
359 |
360 | if (!$statement)
361 | {
362 | $this->errorInfo = $this->pdo->errorInfo();
363 | $this->statement = null;
364 |
365 | return false;
366 | }
367 |
368 | $this->statement = $statement;
369 |
370 | foreach ($map as $key => $value)
371 | {
372 | $statement->bindValue($key, $value[ 0 ], $value[ 1 ]);
373 | }
374 |
375 | $execute = $statement->execute();
376 |
377 | $this->errorInfo = $statement->errorInfo();
378 |
379 | if (!$execute)
380 | {
381 | $this->statement = null;
382 | }
383 |
384 | return $statement;
385 | }
386 |
387 | protected function generate($query, $map)
388 | {
389 | $identifier = [
390 | 'mysql' => '`$1`',
391 | 'mssql' => '[$1]'
392 | ];
393 |
394 | $query = preg_replace(
395 | '/"([a-zA-Z0-9_]+)"/i',
396 | isset($identifier[ $this->type ]) ? $identifier[ $this->type ] : '"$1"',
397 | $query
398 | );
399 |
400 | foreach ($map as $key => $value)
401 | {
402 | if ($value[ 1 ] === PDO::PARAM_STR)
403 | {
404 | $replace = $this->quote($value[ 0 ]);
405 | }
406 | elseif ($value[ 1 ] === PDO::PARAM_NULL)
407 | {
408 | $replace = 'NULL';
409 | }
410 | elseif ($value[ 1 ] === PDO::PARAM_LOB)
411 | {
412 | $replace = '{LOB_DATA}';
413 | }
414 | else
415 | {
416 | $replace = $value[ 0 ];
417 | }
418 |
419 | $query = str_replace($key, $replace, $query);
420 | }
421 |
422 | return $query;
423 | }
424 |
425 | public static function raw($string, $map = [])
426 | {
427 | $raw = new Raw();
428 |
429 | $raw->map = $map;
430 | $raw->value = $string;
431 |
432 | return $raw;
433 | }
434 |
435 | protected function isRaw($object)
436 | {
437 | return $object instanceof Raw;
438 | }
439 |
440 | protected function buildRaw($raw, &$map)
441 | {
442 | if (!$this->isRaw($raw))
443 | {
444 | return false;
445 | }
446 |
447 | $query = preg_replace_callback(
448 | '/(([`\']).*?)?((FROM|TABLE|INTO|UPDATE|JOIN)\s*)?\<(([a-zA-Z0-9_]+)(\.[a-zA-Z0-9_]+)?)\>(.*?\2)?/i',
449 | function ($matches)
450 | {
451 | if (!empty($matches[ 2 ]) && isset($matches[ 8 ]))
452 | {
453 | return $matches[ 0 ];
454 | }
455 |
456 | if (!empty($matches[ 4 ]))
457 | {
458 | return $matches[ 1 ] . $matches[ 4 ] . ' ' . $this->tableQuote($matches[ 5 ]);
459 | }
460 |
461 | return $matches[ 1 ] . $this->columnQuote($matches[ 5 ]);
462 | },
463 | $raw->value);
464 |
465 | $raw_map = $raw->map;
466 |
467 | if (!empty($raw_map))
468 | {
469 | foreach ($raw_map as $key => $value)
470 | {
471 | $map[ $key ] = $this->typeMap($value, gettype($value));
472 | }
473 | }
474 |
475 | return $query;
476 | }
477 |
478 | public function quote($string)
479 | {
480 | return $this->pdo->quote($string);
481 | }
482 |
483 | protected function tableQuote($table)
484 | {
485 | if (!preg_match('/^[a-zA-Z0-9_]+$/i', $table))
486 | {
487 | throw new InvalidArgumentException("Incorrect table name \"$table\"");
488 | }
489 |
490 | return '"' . $this->prefix . $table . '"';
491 | }
492 |
493 | protected function mapKey()
494 | {
495 | return ':MeDoO_' . $this->guid++ . '_mEdOo';
496 | }
497 |
498 | protected function typeMap($value, $type)
499 | {
500 | $map = [
501 | 'NULL' => PDO::PARAM_NULL,
502 | 'integer' => PDO::PARAM_INT,
503 | 'double' => PDO::PARAM_STR,
504 | 'boolean' => PDO::PARAM_BOOL,
505 | 'string' => PDO::PARAM_STR,
506 | 'object' => PDO::PARAM_STR,
507 | 'resource' => PDO::PARAM_LOB
508 | ];
509 |
510 | if ($type === 'boolean')
511 | {
512 | $value = ($value ? '1' : '0');
513 | }
514 | elseif ($type === 'NULL')
515 | {
516 | $value = null;
517 | }
518 |
519 | return [$value, $map[ $type ]];
520 | }
521 |
522 | protected function columnQuote($string)
523 | {
524 | if (!preg_match('/^[a-zA-Z0-9_]+(\.?[a-zA-Z0-9_]+)?$/i', $string))
525 | {
526 | throw new InvalidArgumentException("Incorrect column name \"$string\"");
527 | }
528 |
529 | if (strpos($string, '.') !== false)
530 | {
531 | return '"' . $this->prefix . str_replace('.', '"."', $string) . '"';
532 | }
533 |
534 | return '"' . $string . '"';
535 | }
536 |
537 | protected function columnPush(&$columns, &$map, $root, $is_join = false)
538 | {
539 | if ($columns === '*')
540 | {
541 | return $columns;
542 | }
543 |
544 | $stack = [];
545 |
546 | if (is_string($columns))
547 | {
548 | $columns = [$columns];
549 | }
550 |
551 | foreach ($columns as $key => $value)
552 | {
553 | if (!is_int($key) && is_array($value) && $root && count(array_keys($columns)) === 1)
554 | {
555 | $stack[] = $this->columnQuote($key);
556 |
557 | $stack[] = $this->columnPush($value, $map, false, $is_join);
558 | }
559 | elseif (is_array($value))
560 | {
561 | $stack[] = $this->columnPush($value, $map, false, $is_join);
562 | }
563 | elseif (!is_int($key) && $raw = $this->buildRaw($value, $map))
564 | {
565 | preg_match('/(?[a-zA-Z0-9_\.]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $match);
566 |
567 | $stack[] = $raw . ' AS ' . $this->columnQuote($match[ 'column' ]);
568 | }
569 | elseif (is_int($key) && is_string($value))
570 | {
571 | if ($is_join && strpos($value, '*') !== false)
572 | {
573 | throw new InvalidArgumentException('Cannot use table.* to select all columns while joining table');
574 | }
575 |
576 | preg_match('/(?[a-zA-Z0-9_\.]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $match);
577 |
578 | if (!empty($match[ 'alias' ]))
579 | {
580 | $stack[] = $this->columnQuote($match[ 'column' ]) . ' AS ' . $this->columnQuote($match[ 'alias' ]);
581 |
582 | $columns[ $key ] = $match[ 'alias' ];
583 |
584 | if (!empty($match[ 'type' ]))
585 | {
586 | $columns[ $key ] .= ' [' . $match[ 'type' ] . ']';
587 | }
588 | }
589 | else
590 | {
591 | $stack[] = $this->columnQuote($match[ 'column' ]);
592 | }
593 | }
594 | }
595 |
596 | return implode(',', $stack);
597 | }
598 |
599 | protected function arrayQuote($array)
600 | {
601 | $stack = [];
602 |
603 | foreach ($array as $value)
604 | {
605 | $stack[] = is_int($value) ? $value : $this->pdo->quote($value);
606 | }
607 |
608 | return implode(',', $stack);
609 | }
610 |
611 | protected function innerConjunct($data, $map, $conjunctor, $outer_conjunctor)
612 | {
613 | $stack = [];
614 |
615 | foreach ($data as $value)
616 | {
617 | $stack[] = '(' . $this->dataImplode($value, $map, $conjunctor) . ')';
618 | }
619 |
620 | return implode($outer_conjunctor . ' ', $stack);
621 | }
622 |
623 | protected function dataImplode($data, &$map, $conjunctor)
624 | {
625 | $stack = [];
626 |
627 | foreach ($data as $key => $value)
628 | {
629 | $type = gettype($value);
630 |
631 | if (
632 | $type === 'array' &&
633 | preg_match("/^(AND|OR)(\s+#.*)?$/", $key, $relation_match)
634 | )
635 | {
636 | $relationship = $relation_match[ 1 ];
637 |
638 | $stack[] = $value !== array_keys(array_keys($value)) ?
639 | '(' . $this->dataImplode($value, $map, ' ' . $relationship) . ')' :
640 | '(' . $this->innerConjunct($value, $map, ' ' . $relationship, $conjunctor) . ')';
641 |
642 | continue;
643 | }
644 |
645 | $map_key = $this->mapKey();
646 |
647 | if (
648 | is_int($key) &&
649 | preg_match('/([a-zA-Z0-9_\.]+)\[(?\>\=?|\<\=?|\!?\=)\]([a-zA-Z0-9_\.]+)/i', $value, $match)
650 | )
651 | {
652 | $stack[] = $this->columnQuote($match[ 1 ]) . ' ' . $match[ 'operator' ] . ' ' . $this->columnQuote($match[ 3 ]);
653 | }
654 | else
655 | {
656 | preg_match('/([a-zA-Z0-9_\.]+)(\[(?\>\=?|\<\=?|\!|\<\>|\>\<|\!?~|REGEXP)\])?/i', $key, $match);
657 | $column = $this->columnQuote($match[ 1 ]);
658 |
659 | if (isset($match[ 'operator' ]))
660 | {
661 | $operator = $match[ 'operator' ];
662 |
663 | if (in_array($operator, ['>', '>=', '<', '<=']))
664 | {
665 | $condition = $column . ' ' . $operator . ' ';
666 |
667 | if (is_numeric($value))
668 | {
669 | $condition .= $map_key;
670 | $map[ $map_key ] = [$value, is_float($value) ? PDO::PARAM_STR : PDO::PARAM_INT];
671 | }
672 | elseif ($raw = $this->buildRaw($value, $map))
673 | {
674 | $condition .= $raw;
675 | }
676 | else
677 | {
678 | $condition .= $map_key;
679 | $map[ $map_key ] = [$value, PDO::PARAM_STR];
680 | }
681 |
682 | $stack[] = $condition;
683 | }
684 | elseif ($operator === '!')
685 | {
686 | switch ($type)
687 | {
688 | case 'NULL':
689 | $stack[] = $column . ' IS NOT NULL';
690 | break;
691 |
692 | case 'array':
693 | $placeholders = [];
694 |
695 | foreach ($value as $index => $item)
696 | {
697 | $stack_key = $map_key . $index . '_i';
698 |
699 | $placeholders[] = $stack_key;
700 | $map[ $stack_key ] = $this->typeMap($item, gettype($item));
701 | }
702 |
703 | $stack[] = $column . ' NOT IN (' . implode(', ', $placeholders) . ')';
704 | break;
705 |
706 | case 'object':
707 | if ($raw = $this->buildRaw($value, $map))
708 | {
709 | $stack[] = $column . ' != ' . $raw;
710 | }
711 | break;
712 |
713 | case 'integer':
714 | case 'double':
715 | case 'boolean':
716 | case 'string':
717 | $stack[] = $column . ' != ' . $map_key;
718 | $map[ $map_key ] = $this->typeMap($value, $type);
719 | break;
720 | }
721 | }
722 | elseif ($operator === '~' || $operator === '!~')
723 | {
724 | if ($type !== 'array')
725 | {
726 | $value = [ $value ];
727 | }
728 |
729 | $connector = ' OR ';
730 | $data = array_values($value);
731 |
732 | if (is_array($data[ 0 ]))
733 | {
734 | if (isset($value[ 'AND' ]) || isset($value[ 'OR' ]))
735 | {
736 | $connector = ' ' . array_keys($value)[ 0 ] . ' ';
737 | $value = $data[ 0 ];
738 | }
739 | }
740 |
741 | $like_clauses = [];
742 |
743 | foreach ($value as $index => $item)
744 | {
745 | $item = strval($item);
746 |
747 | if (!preg_match('/(\[.+\]|[\*\?\!\%#^-_]|%.+|.+%)/', $item))
748 | {
749 | $item = '%' . $item . '%';
750 | }
751 |
752 | $like_clauses[] = $column . ($operator === '!~' ? ' NOT' : '') . ' LIKE ' . $map_key . 'L' . $index;
753 | $map[ $map_key . 'L' . $index ] = [$item, PDO::PARAM_STR];
754 | }
755 |
756 | $stack[] = '(' . implode($connector, $like_clauses) . ')';
757 | }
758 | elseif ($operator === '<>' || $operator === '><')
759 | {
760 | if ($type === 'array')
761 | {
762 | if ($operator === '><')
763 | {
764 | $column .= ' NOT';
765 | }
766 |
767 | $stack[] = '(' . $column . ' BETWEEN ' . $map_key . 'a AND ' . $map_key . 'b)';
768 |
769 | $data_type = (is_numeric($value[ 0 ]) && is_numeric($value[ 1 ])) ? PDO::PARAM_INT : PDO::PARAM_STR;
770 |
771 | $map[ $map_key . 'a' ] = [$value[ 0 ], $data_type];
772 | $map[ $map_key . 'b' ] = [$value[ 1 ], $data_type];
773 | }
774 | }
775 | elseif ($operator === 'REGEXP')
776 | {
777 | $stack[] = $column . ' REGEXP ' . $map_key;
778 | $map[ $map_key ] = [$value, PDO::PARAM_STR];
779 | }
780 | }
781 | else
782 | {
783 | switch ($type)
784 | {
785 | case 'NULL':
786 | $stack[] = $column . ' IS NULL';
787 | break;
788 |
789 | case 'array':
790 | $placeholders = [];
791 |
792 | foreach ($value as $index => $item)
793 | {
794 | $stack_key = $map_key . $index . '_i';
795 |
796 | $placeholders[] = $stack_key;
797 | $map[ $stack_key ] = $this->typeMap($item, gettype($item));
798 | }
799 |
800 | $stack[] = $column . ' IN (' . implode(', ', $placeholders) . ')';
801 | break;
802 |
803 | case 'object':
804 | if ($raw = $this->buildRaw($value, $map))
805 | {
806 | $stack[] = $column . ' = ' . $raw;
807 | }
808 | break;
809 |
810 | case 'integer':
811 | case 'double':
812 | case 'boolean':
813 | case 'string':
814 | $stack[] = $column . ' = ' . $map_key;
815 | $map[ $map_key ] = $this->typeMap($value, $type);
816 | break;
817 | }
818 | }
819 | }
820 | }
821 |
822 | return implode($conjunctor . ' ', $stack);
823 | }
824 |
825 | protected function whereClause($where, &$map)
826 | {
827 | $where_clause = '';
828 |
829 | if (is_array($where))
830 | {
831 | $where_keys = array_keys($where);
832 |
833 | $conditions = array_diff_key($where, array_flip(
834 | ['GROUP', 'ORDER', 'HAVING', 'LIMIT', 'LIKE', 'MATCH']
835 | ));
836 |
837 | if (!empty($conditions))
838 | {
839 | $where_clause = ' WHERE ' . $this->dataImplode($conditions, $map, ' AND');
840 | }
841 |
842 | if (isset($where[ 'MATCH' ]) && $this->type === 'mysql')
843 | {
844 | $MATCH = $where[ 'MATCH' ];
845 |
846 | if (is_array($MATCH) && isset($MATCH[ 'columns' ], $MATCH[ 'keyword' ]))
847 | {
848 | $mode = '';
849 |
850 | $mode_array = [
851 | 'natural' => 'IN NATURAL LANGUAGE MODE',
852 | 'natural+query' => 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION',
853 | 'boolean' => 'IN BOOLEAN MODE',
854 | 'query' => 'WITH QUERY EXPANSION'
855 | ];
856 |
857 | if (isset($MATCH[ 'mode' ], $mode_array[ $MATCH[ 'mode' ] ]))
858 | {
859 | $mode = ' ' . $mode_array[ $MATCH[ 'mode' ] ];
860 | }
861 |
862 | $columns = implode(', ', array_map([$this, 'columnQuote'], $MATCH[ 'columns' ]));
863 | $map_key = $this->mapKey();
864 | $map[ $map_key ] = [$MATCH[ 'keyword' ], PDO::PARAM_STR];
865 |
866 | $where_clause .= ($where_clause !== '' ? ' AND ' : ' WHERE') . ' MATCH (' . $columns . ') AGAINST (' . $map_key . $mode . ')';
867 | }
868 | }
869 |
870 | if (isset($where[ 'GROUP' ]))
871 | {
872 | $GROUP = $where[ 'GROUP' ];
873 |
874 | if (is_array($GROUP))
875 | {
876 | $stack = [];
877 |
878 | foreach ($GROUP as $column => $value)
879 | {
880 | $stack[] = $this->columnQuote($value);
881 | }
882 |
883 | $where_clause .= ' GROUP BY ' . implode(',', $stack);
884 | }
885 | elseif ($raw = $this->buildRaw($GROUP, $map))
886 | {
887 | $where_clause .= ' GROUP BY ' . $raw;
888 | }
889 | else
890 | {
891 | $where_clause .= ' GROUP BY ' . $this->columnQuote($GROUP);
892 | }
893 |
894 | if (isset($where[ 'HAVING' ]))
895 | {
896 | if ($raw = $this->buildRaw($where[ 'HAVING' ], $map))
897 | {
898 | $where_clause .= ' HAVING ' . $raw;
899 | }
900 | else
901 | {
902 | $where_clause .= ' HAVING ' . $this->dataImplode($where[ 'HAVING' ], $map, ' AND');
903 | }
904 | }
905 | }
906 |
907 | if (isset($where[ 'ORDER' ]))
908 | {
909 | $ORDER = $where[ 'ORDER' ];
910 |
911 | if (is_array($ORDER))
912 | {
913 | $stack = [];
914 |
915 | foreach ($ORDER as $column => $value)
916 | {
917 | if (is_array($value))
918 | {
919 | $stack[] = 'FIELD(' . $this->columnQuote($column) . ', ' . $this->arrayQuote($value) . ')';
920 | }
921 | elseif ($value === 'ASC' || $value === 'DESC')
922 | {
923 | $stack[] = $this->columnQuote($column) . ' ' . $value;
924 | }
925 | elseif (is_int($column))
926 | {
927 | $stack[] = $this->columnQuote($value);
928 | }
929 | }
930 |
931 | $where_clause .= ' ORDER BY ' . implode(',', $stack);
932 | }
933 | elseif ($raw = $this->buildRaw($ORDER, $map))
934 | {
935 | $where_clause .= ' ORDER BY ' . $raw;
936 | }
937 | else
938 | {
939 | $where_clause .= ' ORDER BY ' . $this->columnQuote($ORDER);
940 | }
941 |
942 | if (
943 | isset($where[ 'LIMIT' ]) &&
944 | in_array($this->type, ['oracle', 'mssql'])
945 | )
946 | {
947 | $LIMIT = $where[ 'LIMIT' ];
948 |
949 | if (is_numeric($LIMIT))
950 | {
951 | $LIMIT = [0, $LIMIT];
952 | }
953 |
954 | if (
955 | is_array($LIMIT) &&
956 | is_numeric($LIMIT[ 0 ]) &&
957 | is_numeric($LIMIT[ 1 ])
958 | )
959 | {
960 | $where_clause .= ' OFFSET ' . $LIMIT[ 0 ] . ' ROWS FETCH NEXT ' . $LIMIT[ 1 ] . ' ROWS ONLY';
961 | }
962 | }
963 | }
964 |
965 | if (isset($where[ 'LIMIT' ]) && !in_array($this->type, ['oracle', 'mssql']))
966 | {
967 | $LIMIT = $where[ 'LIMIT' ];
968 |
969 | if (is_numeric($LIMIT))
970 | {
971 | $where_clause .= ' LIMIT ' . $LIMIT;
972 | }
973 | elseif (
974 | is_array($LIMIT) &&
975 | is_numeric($LIMIT[ 0 ]) &&
976 | is_numeric($LIMIT[ 1 ])
977 | )
978 | {
979 | $where_clause .= ' LIMIT ' . $LIMIT[ 1 ] . ' OFFSET ' . $LIMIT[ 0 ];
980 | }
981 | }
982 | }
983 | elseif ($raw = $this->buildRaw($where, $map))
984 | {
985 | $where_clause .= ' ' . $raw;
986 | }
987 |
988 | return $where_clause;
989 | }
990 |
991 | protected function selectContext($table, &$map, $join, &$columns = null, $where = null, $column_fn = null)
992 | {
993 | preg_match('/(?[a-zA-Z0-9_]+)\s*\((?[a-zA-Z0-9_]+)\)/i', $table, $table_match);
994 |
995 | if (isset($table_match[ 'table' ], $table_match[ 'alias' ]))
996 | {
997 | $table = $this->tableQuote($table_match[ 'table' ]);
998 |
999 | $table_query = $table . ' AS ' . $this->tableQuote($table_match[ 'alias' ]);
1000 | }
1001 | else
1002 | {
1003 | $table = $this->tableQuote($table);
1004 |
1005 | $table_query = $table;
1006 | }
1007 |
1008 | $is_join = false;
1009 | $join_key = is_array($join) ? array_keys($join) : null;
1010 |
1011 | if (
1012 | isset($join_key[ 0 ]) &&
1013 | strpos($join_key[ 0 ], '[') === 0
1014 | )
1015 | {
1016 | $is_join = true;
1017 | $table_query .= ' ' . $this->buildJoin($table, $join);
1018 | }
1019 | else
1020 | {
1021 | if (is_null($columns))
1022 | {
1023 | if (
1024 | !is_null($where) ||
1025 | (is_array($join) && isset($column_fn))
1026 | )
1027 | {
1028 | $where = $join;
1029 | $columns = null;
1030 | }
1031 | else
1032 | {
1033 | $where = null;
1034 | $columns = $join;
1035 | }
1036 | }
1037 | else
1038 | {
1039 | $where = $columns;
1040 | $columns = $join;
1041 | }
1042 | }
1043 |
1044 | if (isset($column_fn))
1045 | {
1046 | if ($column_fn === 1)
1047 | {
1048 | $column = '1';
1049 |
1050 | if (is_null($where))
1051 | {
1052 | $where = $columns;
1053 | }
1054 | }
1055 | elseif ($raw = $this->buildRaw($column_fn, $map))
1056 | {
1057 | $column = $raw;
1058 | }
1059 | else
1060 | {
1061 | if (empty($columns) || $this->isRaw($columns))
1062 | {
1063 | $columns = '*';
1064 | $where = $join;
1065 | }
1066 |
1067 | $column = $column_fn . '(' . $this->columnPush($columns, $map, true) . ')';
1068 | }
1069 | }
1070 | else
1071 | {
1072 | $column = $this->columnPush($columns, $map, true, $is_join);
1073 | }
1074 |
1075 | return 'SELECT ' . $column . ' FROM ' . $table_query . $this->whereClause($where, $map);
1076 | }
1077 |
1078 | protected function buildJoin($table, $join)
1079 | {
1080 | $table_join = [];
1081 |
1082 | $join_array = [
1083 | '>' => 'LEFT',
1084 | '<' => 'RIGHT',
1085 | '<>' => 'FULL',
1086 | '><' => 'INNER'
1087 | ];
1088 |
1089 | foreach($join as $sub_table => $relation)
1090 | {
1091 | preg_match('/(\[(?\<\>?|\>\)\])?(?[a-zA-Z0-9_]+)\s?(\((?[a-zA-Z0-9_]+)\))?/', $sub_table, $match);
1092 |
1093 | if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '')
1094 | {
1095 | if (is_string($relation))
1096 | {
1097 | $relation = 'USING ("' . $relation . '")';
1098 | }
1099 |
1100 | if (is_array($relation))
1101 | {
1102 | // For ['column1', 'column2']
1103 | if (isset($relation[ 0 ]))
1104 | {
1105 | $relation = 'USING ("' . implode('", "', $relation) . '")';
1106 | }
1107 | else
1108 | {
1109 | $joins = [];
1110 |
1111 | foreach ($relation as $key => $value)
1112 | {
1113 | $joins[] = (
1114 | strpos($key, '.') > 0 ?
1115 | // For ['tableB.column' => 'column']
1116 | $this->columnQuote($key) :
1117 |
1118 | // For ['column1' => 'column2']
1119 | $table . '."' . $key . '"'
1120 | ) .
1121 | ' = ' .
1122 | $this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"';
1123 | }
1124 |
1125 | $relation = 'ON ' . implode(' AND ', $joins);
1126 | }
1127 | }
1128 |
1129 | $table_name = $this->tableQuote($match[ 'table' ]) . ' ';
1130 |
1131 | if (isset($match[ 'alias' ]))
1132 | {
1133 | $table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' ';
1134 | }
1135 |
1136 | $table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation;
1137 | }
1138 | }
1139 |
1140 | return implode(' ', $table_join);
1141 | }
1142 |
1143 | protected function columnMap($columns, &$stack, $root)
1144 | {
1145 | if ($columns === '*')
1146 | {
1147 | return $stack;
1148 | }
1149 |
1150 | foreach ($columns as $key => $value)
1151 | {
1152 | if (is_int($key))
1153 | {
1154 | preg_match('/([a-zA-Z0-9_]+\.)?(?[a-zA-Z0-9_]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $key_match);
1155 |
1156 | $column_key = !empty($key_match[ 'alias' ]) ?
1157 | $key_match[ 'alias' ] :
1158 | $key_match[ 'column' ];
1159 |
1160 | if (isset($key_match[ 'type' ]))
1161 | {
1162 | $stack[ $value ] = [$column_key, $key_match[ 'type' ]];
1163 | }
1164 | else
1165 | {
1166 | $stack[ $value ] = [$column_key, 'String'];
1167 | }
1168 | }
1169 | elseif ($this->isRaw($value))
1170 | {
1171 | preg_match('/([a-zA-Z0-9_]+\.)?(?[a-zA-Z0-9_]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $key_match);
1172 |
1173 | $column_key = $key_match[ 'column' ];
1174 |
1175 | if (isset($key_match[ 'type' ]))
1176 | {
1177 | $stack[ $key ] = [$column_key, $key_match[ 'type' ]];
1178 | }
1179 | else
1180 | {
1181 | $stack[ $key ] = [$column_key, 'String'];
1182 | }
1183 | }
1184 | elseif (!is_int($key) && is_array($value))
1185 | {
1186 | if ($root && count(array_keys($columns)) === 1)
1187 | {
1188 | $stack[ $key ] = [$key, 'String'];
1189 | }
1190 |
1191 | $this->columnMap($value, $stack, false);
1192 | }
1193 | }
1194 |
1195 | return $stack;
1196 | }
1197 |
1198 | protected function dataMap($data, $columns, $column_map, &$stack, $root, &$result)
1199 | {
1200 | if ($root)
1201 | {
1202 | $columns_key = array_keys($columns);
1203 |
1204 | if (count($columns_key) === 1 && is_array($columns[$columns_key[0]]))
1205 | {
1206 | $index_key = array_keys($columns)[0];
1207 | $data_key = preg_replace("/^[a-zA-Z0-9_]+\./i", "", $index_key);
1208 |
1209 | $current_stack = [];
1210 |
1211 | foreach ($data as $item)
1212 | {
1213 | $this->dataMap($data, $columns[ $index_key ], $column_map, $current_stack, false, $result);
1214 |
1215 | $index = $data[ $data_key ];
1216 |
1217 | $result[ $index ] = $current_stack;
1218 | }
1219 | }
1220 | else
1221 | {
1222 | $current_stack = [];
1223 |
1224 | $this->dataMap($data, $columns, $column_map, $current_stack, false, $result);
1225 |
1226 | $result[] = $current_stack;
1227 | }
1228 |
1229 | return;
1230 | }
1231 |
1232 | foreach ($columns as $key => $value)
1233 | {
1234 | $isRaw = $this->isRaw($value);
1235 |
1236 | if (is_int($key) || $isRaw)
1237 | {
1238 | $map = $column_map[ $isRaw ? $key : $value ];
1239 |
1240 | $column_key = $map[ 0 ];
1241 |
1242 | $item = $data[ $column_key ];
1243 |
1244 | if (isset($map[ 1 ]))
1245 | {
1246 | if ($isRaw && in_array($map[ 1 ], ['Object', 'JSON']))
1247 | {
1248 | continue;
1249 | }
1250 |
1251 | if (is_null($item))
1252 | {
1253 | $stack[ $column_key ] = null;
1254 | continue;
1255 | }
1256 |
1257 | switch ($map[ 1 ])
1258 | {
1259 | case 'Number':
1260 | $stack[ $column_key ] = (double) $item;
1261 | break;
1262 |
1263 | case 'Int':
1264 | $stack[ $column_key ] = (int) $item;
1265 | break;
1266 |
1267 | case 'Bool':
1268 | $stack[ $column_key ] = (bool) $item;
1269 | break;
1270 |
1271 | case 'Object':
1272 | $stack[ $column_key ] = unserialize($item);
1273 | break;
1274 |
1275 | case 'JSON':
1276 | $stack[ $column_key ] = json_decode($item, true);
1277 | break;
1278 |
1279 | case 'String':
1280 | $stack[ $column_key ] = $item;
1281 | break;
1282 | }
1283 | }
1284 | else
1285 | {
1286 | $stack[ $column_key ] = $item;
1287 | }
1288 | }
1289 | else
1290 | {
1291 | $current_stack = [];
1292 |
1293 | $this->dataMap($data, $value, $column_map, $current_stack, false, $result);
1294 |
1295 | $stack[ $key ] = $current_stack;
1296 | }
1297 | }
1298 | }
1299 |
1300 | public function create($table, $columns, $options = null)
1301 | {
1302 | $stack = [];
1303 |
1304 | $tableName = $this->prefix . $table;
1305 |
1306 | foreach ($columns as $name => $definition)
1307 | {
1308 | if (is_int($name))
1309 | {
1310 | $stack[] = preg_replace('/\<([a-zA-Z0-9_]+)\>/i', '"$1"', $definition);
1311 | }
1312 | elseif (is_array($definition))
1313 | {
1314 | $stack[] = $name . ' ' . implode(' ', $definition);
1315 | }
1316 | elseif (is_string($definition))
1317 | {
1318 | $stack[] = $name . ' ' . $this->query($definition);
1319 | }
1320 | }
1321 |
1322 | $table_option = '';
1323 |
1324 | if (is_array($options))
1325 | {
1326 | $option_stack = [];
1327 |
1328 | foreach ($options as $key => $value)
1329 | {
1330 | if (is_string($value) || is_int($value))
1331 | {
1332 | $option_stack[] = "$key = $value";
1333 | }
1334 | }
1335 |
1336 | $table_option = ' ' . implode(', ', $option_stack);
1337 | }
1338 | elseif (is_string($options))
1339 | {
1340 | $table_option = ' ' . $options;
1341 | }
1342 |
1343 | return $this->exec("CREATE TABLE IF NOT EXISTS $tableName (" . implode(', ', $stack) . ")$table_option");
1344 | }
1345 |
1346 | public function drop($table)
1347 | {
1348 | $tableName = $this->prefix . $table;
1349 |
1350 | return $this->exec("DROP TABLE IF EXISTS $tableName");
1351 | }
1352 |
1353 | public function select($table, $join, $columns = null, $where = null)
1354 | {
1355 | $map = [];
1356 | $result = [];
1357 | $column_map = [];
1358 |
1359 | $index = 0;
1360 |
1361 | $column = $where === null ? $join : $columns;
1362 |
1363 | $is_single = (is_string($column) && $column !== '*');
1364 |
1365 | $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where), $map);
1366 |
1367 | $this->columnMap($columns, $column_map, true);
1368 |
1369 | if (!$this->statement)
1370 | {
1371 | return false;
1372 | }
1373 |
1374 | if ($columns === '*')
1375 | {
1376 | return $query->fetchAll(PDO::FETCH_ASSOC);
1377 | }
1378 |
1379 | while ($data = $query->fetch(PDO::FETCH_ASSOC))
1380 | {
1381 | $current_stack = [];
1382 |
1383 | $this->dataMap($data, $columns, $column_map, $current_stack, true, $result);
1384 | }
1385 |
1386 | if ($is_single)
1387 | {
1388 | $single_result = [];
1389 | $result_key = $column_map[ $column ][ 0 ];
1390 |
1391 | foreach ($result as $item)
1392 | {
1393 | $single_result[] = $item[ $result_key ];
1394 | }
1395 |
1396 | return $single_result;
1397 | }
1398 |
1399 | return $result;
1400 | }
1401 |
1402 | public function insert($table, $datas)
1403 | {
1404 | $stack = [];
1405 | $columns = [];
1406 | $fields = [];
1407 | $map = [];
1408 |
1409 | if (!isset($datas[ 0 ]))
1410 | {
1411 | $datas = [$datas];
1412 | }
1413 |
1414 | foreach ($datas as $data)
1415 | {
1416 | foreach ($data as $key => $value)
1417 | {
1418 | $columns[] = $key;
1419 | }
1420 | }
1421 |
1422 | $columns = array_unique($columns);
1423 |
1424 | foreach ($datas as $data)
1425 | {
1426 | $values = [];
1427 |
1428 | foreach ($columns as $key)
1429 | {
1430 | if ($raw = $this->buildRaw($data[ $key ], $map))
1431 | {
1432 | $values[] = $raw;
1433 | continue;
1434 | }
1435 |
1436 | $map_key = $this->mapKey();
1437 |
1438 | $values[] = $map_key;
1439 |
1440 | if (!isset($data[ $key ]))
1441 | {
1442 | $map[ $map_key ] = [null, PDO::PARAM_NULL];
1443 | }
1444 | else
1445 | {
1446 | $value = $data[ $key ];
1447 |
1448 | $type = gettype($value);
1449 |
1450 | switch ($type)
1451 | {
1452 | case 'array':
1453 | $map[ $map_key ] = [
1454 | strpos($key, '[JSON]') === strlen($key) - 6 ?
1455 | json_encode($value) :
1456 | serialize($value),
1457 | PDO::PARAM_STR
1458 | ];
1459 | break;
1460 |
1461 | case 'object':
1462 | $value = serialize($value);
1463 |
1464 | case 'NULL':
1465 | case 'resource':
1466 | case 'boolean':
1467 | case 'integer':
1468 | case 'double':
1469 | case 'string':
1470 | $map[ $map_key ] = $this->typeMap($value, $type);
1471 | break;
1472 | }
1473 | }
1474 | }
1475 |
1476 | $stack[] = '(' . implode(', ', $values) . ')';
1477 | }
1478 |
1479 | foreach ($columns as $key)
1480 | {
1481 | $fields[] = $this->columnQuote(preg_replace("/(\s*\[JSON\]$)/i", '', $key));
1482 | }
1483 |
1484 | return $this->exec('INSERT INTO ' . $this->tableQuote($table) . ' (' . implode(', ', $fields) . ') VALUES ' . implode(', ', $stack), $map);
1485 | }
1486 |
1487 | public function update($table, $data, $where = null)
1488 | {
1489 | $fields = [];
1490 | $map = [];
1491 |
1492 | foreach ($data as $key => $value)
1493 | {
1494 | $column = $this->columnQuote(preg_replace("/(\s*\[(JSON|\+|\-|\*|\/)\]$)/i", '', $key));
1495 |
1496 | if ($raw = $this->buildRaw($value, $map))
1497 | {
1498 | $fields[] = $column . ' = ' . $raw;
1499 | continue;
1500 | }
1501 |
1502 | $map_key = $this->mapKey();
1503 |
1504 | preg_match('/(?[a-zA-Z0-9_]+)(\[(?\+|\-|\*|\/)\])?/i', $key, $match);
1505 |
1506 | if (isset($match[ 'operator' ]))
1507 | {
1508 | if (is_numeric($value))
1509 | {
1510 | $fields[] = $column . ' = ' . $column . ' ' . $match[ 'operator' ] . ' ' . $value;
1511 | }
1512 | }
1513 | else
1514 | {
1515 | $fields[] = $column . ' = ' . $map_key;
1516 |
1517 | $type = gettype($value);
1518 |
1519 | switch ($type)
1520 | {
1521 | case 'array':
1522 | $map[ $map_key ] = [
1523 | strpos($key, '[JSON]') === strlen($key) - 6 ?
1524 | json_encode($value) :
1525 | serialize($value),
1526 | PDO::PARAM_STR
1527 | ];
1528 | break;
1529 |
1530 | case 'object':
1531 | $value = serialize($value);
1532 |
1533 | case 'NULL':
1534 | case 'resource':
1535 | case 'boolean':
1536 | case 'integer':
1537 | case 'double':
1538 | case 'string':
1539 | $map[ $map_key ] = $this->typeMap($value, $type);
1540 | break;
1541 | }
1542 | }
1543 | }
1544 |
1545 | return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $fields) . $this->whereClause($where, $map), $map);
1546 | }
1547 |
1548 | public function delete($table, $where)
1549 | {
1550 | $map = [];
1551 |
1552 | return $this->exec('DELETE FROM ' . $this->tableQuote($table) . $this->whereClause($where, $map), $map);
1553 | }
1554 |
1555 | public function replace($table, $columns, $where = null)
1556 | {
1557 | if (!is_array($columns) || empty($columns))
1558 | {
1559 | return false;
1560 | }
1561 |
1562 | $map = [];
1563 | $stack = [];
1564 |
1565 | foreach ($columns as $column => $replacements)
1566 | {
1567 | if (is_array($replacements))
1568 | {
1569 | foreach ($replacements as $old => $new)
1570 | {
1571 | $map_key = $this->mapKey();
1572 |
1573 | $stack[] = $this->columnQuote($column) . ' = REPLACE(' . $this->columnQuote($column) . ', ' . $map_key . 'a, ' . $map_key . 'b)';
1574 |
1575 | $map[ $map_key . 'a' ] = [$old, PDO::PARAM_STR];
1576 | $map[ $map_key . 'b' ] = [$new, PDO::PARAM_STR];
1577 | }
1578 | }
1579 | }
1580 |
1581 | if (!empty($stack))
1582 | {
1583 | return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $stack) . $this->whereClause($where, $map), $map);
1584 | }
1585 |
1586 | return false;
1587 | }
1588 |
1589 | public function get($table, $join = null, $columns = null, $where = null)
1590 | {
1591 | $map = [];
1592 | $result = [];
1593 | $column_map = [];
1594 | $current_stack = [];
1595 |
1596 | if ($where === null)
1597 | {
1598 | $column = $join;
1599 | unset($columns[ 'LIMIT' ]);
1600 | }
1601 | else
1602 | {
1603 | $column = $columns;
1604 | unset($where[ 'LIMIT' ]);
1605 | }
1606 |
1607 | $is_single = (is_string($column) && $column !== '*');
1608 |
1609 | $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where) . ' LIMIT 1', $map);
1610 |
1611 | if (!$this->statement)
1612 | {
1613 | return false;
1614 | }
1615 |
1616 | $data = $query->fetchAll(PDO::FETCH_ASSOC);
1617 |
1618 | if (isset($data[ 0 ]))
1619 | {
1620 | if ($column === '*')
1621 | {
1622 | return $data[ 0 ];
1623 | }
1624 |
1625 | $this->columnMap($columns, $column_map, true);
1626 |
1627 | $this->dataMap($data[ 0 ], $columns, $column_map, $current_stack, true, $result);
1628 |
1629 | if ($is_single)
1630 | {
1631 | return $result[ 0 ][ $column_map[ $column ][ 0 ] ];
1632 | }
1633 |
1634 | return $result[ 0 ];
1635 | }
1636 | }
1637 |
1638 | public function has($table, $join, $where = null)
1639 | {
1640 | $map = [];
1641 | $column = null;
1642 |
1643 | if ($this->type === 'mssql')
1644 | {
1645 | $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, Medoo::raw('TOP 1 1')), $map);
1646 | }
1647 | else
1648 | {
1649 | $query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map);
1650 | }
1651 |
1652 | if (!$this->statement)
1653 | {
1654 | return false;
1655 | }
1656 |
1657 | $result = $query->fetchColumn();
1658 |
1659 | return $result === '1' || $result === 1 || $result === true;
1660 | }
1661 |
1662 | public function rand($table, $join = null, $columns = null, $where = null)
1663 | {
1664 | $type = $this->type;
1665 |
1666 | $order = 'RANDOM()';
1667 |
1668 | if ($type === 'mysql')
1669 | {
1670 | $order = 'RAND()';
1671 | }
1672 | elseif ($type === 'mssql')
1673 | {
1674 | $order = 'NEWID()';
1675 | }
1676 |
1677 | $order_raw = $this->raw($order);
1678 |
1679 | if ($where === null)
1680 | {
1681 | if ($columns === null)
1682 | {
1683 | $columns = [
1684 | 'ORDER' => $order_raw
1685 | ];
1686 | }
1687 | else
1688 | {
1689 | $column = $join;
1690 | unset($columns[ 'ORDER' ]);
1691 |
1692 | $columns[ 'ORDER' ] = $order_raw;
1693 | }
1694 | }
1695 | else
1696 | {
1697 | unset($where[ 'ORDER' ]);
1698 |
1699 | $where[ 'ORDER' ] = $order_raw;
1700 | }
1701 |
1702 | return $this->select($table, $join, $columns, $where);
1703 | }
1704 |
1705 | private function aggregate($type, $table, $join = null, $column = null, $where = null)
1706 | {
1707 | $map = [];
1708 |
1709 | $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, strtoupper($type)), $map);
1710 |
1711 | if (!$this->statement)
1712 | {
1713 | return false;
1714 | }
1715 |
1716 | $number = $query->fetchColumn();
1717 |
1718 | return is_numeric($number) ? $number + 0 : $number;
1719 | }
1720 |
1721 | public function count($table, $join = null, $column = null, $where = null)
1722 | {
1723 | return $this->aggregate('count', $table, $join, $column, $where);
1724 | }
1725 |
1726 | public function avg($table, $join, $column = null, $where = null)
1727 | {
1728 | return $this->aggregate('avg', $table, $join, $column, $where);
1729 | }
1730 |
1731 | public function max($table, $join, $column = null, $where = null)
1732 | {
1733 | return $this->aggregate('max', $table, $join, $column, $where);
1734 | }
1735 |
1736 | public function min($table, $join, $column = null, $where = null)
1737 | {
1738 | return $this->aggregate('min', $table, $join, $column, $where);
1739 | }
1740 |
1741 | public function sum($table, $join, $column = null, $where = null)
1742 | {
1743 | return $this->aggregate('sum', $table, $join, $column, $where);
1744 | }
1745 |
1746 | public function action($actions)
1747 | {
1748 | if (is_callable($actions))
1749 | {
1750 | $this->pdo->beginTransaction();
1751 |
1752 | try {
1753 | $result = $actions($this);
1754 |
1755 | if ($result === false)
1756 | {
1757 | $this->pdo->rollBack();
1758 | }
1759 | else
1760 | {
1761 | $this->pdo->commit();
1762 | }
1763 | }
1764 | catch (Exception $e) {
1765 | $this->pdo->rollBack();
1766 |
1767 | throw $e;
1768 | }
1769 |
1770 | return $result;
1771 | }
1772 |
1773 | return false;
1774 | }
1775 |
1776 | public function id()
1777 | {
1778 | if ($this->statement == null)
1779 | {
1780 | return null;
1781 | }
1782 |
1783 | $type = $this->type;
1784 |
1785 | if ($type === 'oracle')
1786 | {
1787 | return 0;
1788 | }
1789 | elseif ($type === 'pgsql')
1790 | {
1791 | return $this->pdo->query('SELECT LASTVAL()')->fetchColumn();
1792 | }
1793 |
1794 | $lastId = $this->pdo->lastInsertId();
1795 |
1796 | if ($lastId != "0" && $lastId != "")
1797 | {
1798 | return $lastId;
1799 | }
1800 |
1801 | return null;
1802 | }
1803 |
1804 | public function debug()
1805 | {
1806 | $this->debug_mode = true;
1807 |
1808 | return $this;
1809 | }
1810 |
1811 | public function error()
1812 | {
1813 | return $this->errorInfo;
1814 | }
1815 |
1816 | public function last()
1817 | {
1818 | $log = end($this->logs);
1819 |
1820 | return $this->generate($log[ 0 ], $log[ 1 ]);
1821 | }
1822 |
1823 | public function log()
1824 | {
1825 | return array_map(function ($log)
1826 | {
1827 | return $this->generate($log[ 0 ], $log[ 1 ]);
1828 | },
1829 | $this->logs
1830 | );
1831 | }
1832 |
1833 | public function info()
1834 | {
1835 | $output = [
1836 | 'server' => 'SERVER_INFO',
1837 | 'driver' => 'DRIVER_NAME',
1838 | 'client' => 'CLIENT_VERSION',
1839 | 'version' => 'SERVER_VERSION',
1840 | 'connection' => 'CONNECTION_STATUS'
1841 | ];
1842 |
1843 | foreach ($output as $key => $value)
1844 | {
1845 | $output[ $key ] = @$this->pdo->getAttribute(constant('PDO::ATTR_' . $value));
1846 | }
1847 |
1848 | $output[ 'dsn' ] = $this->dsn;
1849 |
1850 | return $output;
1851 | }
1852 | }
--------------------------------------------------------------------------------
/lib/3rd_party_helpers/jwt_helper.php:
--------------------------------------------------------------------------------
1 |
15 | * @author Anant Narayanan
16 | * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
17 | * @link https://github.com/firebase/php-jwt
18 | */
19 | class JWT
20 | {
21 | /**
22 | * Decodes a JWT string into a PHP object.
23 | *
24 | * @param string $jwt The JWT
25 | * @param string|null $key The secret key
26 | * @param bool $verify Don't skip verification process
27 | *
28 | * @return object The JWT's payload as a PHP object
29 | * @throws UnexpectedValueException Provided JWT was invalid
30 | * @throws DomainException Algorithm was not provided
31 | *
32 | * @uses jsonDecode
33 | * @uses urlsafeB64Decode
34 | */
35 | public static function decode($jwt, $key = null, $verify = true)
36 | {
37 | $tks = explode('.', $jwt);
38 | if (count($tks) != 3) {
39 | throw new UnexpectedValueException('Wrong number of segments');
40 | }
41 | list($headb64, $bodyb64, $cryptob64) = $tks;
42 | if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
43 | throw new UnexpectedValueException('Invalid segment encoding');
44 | }
45 | if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
46 | throw new UnexpectedValueException('Invalid segment encoding');
47 | }
48 | $sig = JWT::urlsafeB64Decode($cryptob64);
49 | if ($verify) {
50 | if (empty($header->alg)) {
51 | throw new DomainException('Empty algorithm');
52 | }
53 | if ($sig != JWT::sign("$headb64.$bodyb64", $key, $header->alg)) {
54 | throw new UnexpectedValueException('Signature verification failed');
55 | }
56 | }
57 | return $payload;
58 | }
59 | /**
60 | * Converts and signs a PHP object or array into a JWT string.
61 | *
62 | * @param object|array $payload PHP object or array
63 | * @param string $key The secret key
64 | * @param string $algo The signing algorithm. Supported
65 | * algorithms are 'HS256', 'HS384' and 'HS512'
66 | *
67 | * @return string A signed JWT
68 | * @uses jsonEncode
69 | * @uses urlsafeB64Encode
70 | */
71 | public static function encode($payload, $key, $algo = 'HS256')
72 | {
73 | $header = array('typ' => 'JWT', 'alg' => $algo);
74 | $segments = array();
75 | $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
76 | $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
77 | $signing_input = implode('.', $segments);
78 | $signature = JWT::sign($signing_input, $key, $algo);
79 | $segments[] = JWT::urlsafeB64Encode($signature);
80 | return implode('.', $segments);
81 | }
82 | /**
83 | * Sign a string with a given key and algorithm.
84 | *
85 | * @param string $msg The message to sign
86 | * @param string $key The secret key
87 | * @param string $method The signing algorithm. Supported
88 | * algorithms are 'HS256', 'HS384' and 'HS512'
89 | *
90 | * @return string An encrypted message
91 | * @throws DomainException Unsupported algorithm was specified
92 | */
93 | public static function sign($msg, $key, $method = 'HS256')
94 | {
95 | $methods = array(
96 | 'HS256' => 'sha256',
97 | 'HS384' => 'sha384',
98 | 'HS512' => 'sha512',
99 | );
100 | if (empty($methods[$method])) {
101 | throw new DomainException('Algorithm not supported');
102 | }
103 | return hash_hmac($methods[$method], $msg, $key, true);
104 | }
105 | /**
106 | * Decode a JSON string into a PHP object.
107 | *
108 | * @param string $input JSON string
109 | *
110 | * @return object Object representation of JSON string
111 | * @throws DomainException Provided string was invalid JSON
112 | */
113 | public static function jsonDecode($input)
114 | {
115 | $obj = json_decode($input);
116 | if (function_exists('json_last_error') && $errno = json_last_error()) {
117 | JWT::_handleJsonError($errno);
118 | } else if ($obj === null && $input !== 'null') {
119 | throw new DomainException('Null result with non-null input');
120 | }
121 | return $obj;
122 | }
123 | /**
124 | * Encode a PHP object into a JSON string.
125 | *
126 | * @param object|array $input A PHP object or array
127 | *
128 | * @return string JSON representation of the PHP object or array
129 | * @throws DomainException Provided object could not be encoded to valid JSON
130 | */
131 | public static function jsonEncode($input)
132 | {
133 | $json = json_encode($input);
134 | if (function_exists('json_last_error') && $errno = json_last_error()) {
135 | JWT::_handleJsonError($errno);
136 | } else if ($json === 'null' && $input !== null) {
137 | throw new DomainException('Null result with non-null input');
138 | }
139 | return $json;
140 | }
141 | /**
142 | * Decode a string with URL-safe Base64.
143 | *
144 | * @param string $input A Base64 encoded string
145 | *
146 | * @return string A decoded string
147 | */
148 | public static function urlsafeB64Decode($input)
149 | {
150 | $remainder = strlen($input) % 4;
151 | if ($remainder) {
152 | $padlen = 4 - $remainder;
153 | $input .= str_repeat('=', $padlen);
154 | }
155 | return base64_decode(strtr($input, '-_', '+/'));
156 | }
157 | /**
158 | * Encode a string with URL-safe Base64.
159 | *
160 | * @param string $input The string you want encoded
161 | *
162 | * @return string The base64 encode of what you passed in
163 | */
164 | public static function urlsafeB64Encode($input)
165 | {
166 | return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
167 | }
168 | /**
169 | * Helper method to create a JSON error.
170 | *
171 | * @param int $errno An error number from json_last_error()
172 | *
173 | * @return void
174 | */
175 | private static function _handleJsonError($errno)
176 | {
177 | $messages = array(
178 | JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
179 | JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
180 | JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
181 | );
182 | throw new DomainException(
183 | isset($messages[$errno])
184 | ? $messages[$errno]
185 | : 'Unknown JSON error: ' . $errno
186 | );
187 | }
188 | }
--------------------------------------------------------------------------------
/lib/3rd_party_helpers/password_helper.php:
--------------------------------------------------------------------------------
1 | '$1;',
32 | '/(*\w+)[\x00-\x20]+;/u' => '$1;>',
33 | '/(*[0-9A-F]+);*/iu' => '$1;',
34 | //any attribute starting with "on" or xml name space
35 | '#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu' => '$1>',
36 | //javascript: and VB script: protocols
37 | '#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu' => '$1=$2nojavascript...',
38 | '#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu' => '$1=$2novbscript...',
39 | '#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u' => '$1=$2nomozbinding...',
40 | // Only works in IE:
41 | '#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i' => '$1>',
42 | '#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu' => '$1>',
43 | // namespace elements
44 | '#*\w+:\w[^>]*+>#i' => '',
45 | //unwanted tags
46 | '#*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i' => ''
47 | );
48 |
49 | /**
50 | * @var array
51 | */
52 | private $normal_patterns = array(
53 | '\'' => ''',
54 | '"' => '"',
55 | '&' => '&',
56 | '<' => '<',
57 | '>' => '>',
58 | //possible SQL injection remove from string with there is no '
59 | 'SELECT * FROM' => '',
60 | 'SELECT(' => '',
61 | 'SLEEP(' => '',
62 | 'AND (' => '',
63 | ' AND' => '',
64 | '(CASE' => ''
65 | );
66 |
67 | /**
68 | * xss_filter::filter_it()
69 | *
70 | * @access public
71 | * @param string $input
72 | * @return string
73 | */
74 | public function filter_it($input){
75 | $this->input = html_entity_decode($input, ENT_NOQUOTES, 'UTF-8');
76 | $this->normal_replace();
77 | $this->do_grep();
78 | return $this->input;
79 | }
80 |
81 | /**
82 | * xss_filter::allow_http()
83 | *
84 | * @access public
85 | */
86 | public function allow_http(){
87 | $this->allow_http_value = true;
88 | }
89 |
90 | /**
91 | * xss_filter::disallow_http()
92 | *
93 | * @access public
94 | */
95 | public function disallow_http(){
96 | $this->allow_http_value = false;
97 | }
98 |
99 | /**
100 | * xss_filter::remove_get_parameters()
101 | *
102 | * @access public
103 | * @param $url string
104 | * @return string
105 | */
106 | public function remove_get_parameters($url){
107 | return preg_replace('/\?.*/', '', $url);
108 | }
109 |
110 | /**
111 | * xss_filter::normal_replace()
112 | *
113 | * @access private
114 | */
115 | private function normal_replace(){
116 | $this->input = str_replace(array('&', '<', '>'), array('&', '<', '>'), $this->input);
117 | if($this->allow_http_value === false){
118 | $this->input = str_replace(array('&', '%', 'script', 'http', 'localhost'), array('', '', '', '', ''), $this->input);
119 | }
120 | else
121 | {
122 | $this->input = str_replace(array('&', '%', 'script', 'localhost', '../'), array('', '', '', '', ''), $this->input);
123 | }
124 | foreach($this->normal_patterns as $pattern => $replacement){
125 | $this->input = str_replace($pattern,$replacement,$this->input);
126 | }
127 | }
128 |
129 | /**
130 | * xss_filter::do_grep()
131 | *
132 | * @access private
133 | */
134 | private function do_grep(){
135 | foreach($this->preg_patterns as $pattern => $replacement){
136 | $this->input = preg_replace($pattern,$replacement,$this->input);
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/lib/fsl_functions.php:
--------------------------------------------------------------------------------
1 | filter_it($string);
85 | return $string;
86 | }
87 |
88 | /*
89 | * fsl_session_set
90 | *
91 | * sets a new session value with optional timeout in seconds
92 | * also used to set any cookie variable. all data is set encrypted with global key
93 | * @name (string) Name of session
94 | * @value (string) value of session
95 | * @timeoue (string) optional timeout of session
96 | * @return true
97 | */
98 | function fsl_session_set($name,$value,$timeout = NULL){
99 | $_SESSION[$name] = fsl_encrypt($value);
100 | if(!empty($timeout)) $_SESSION[$name.'_timeout'] = $timeout + time();
101 |
102 | return true;
103 | }
104 |
105 | /*
106 | * fsl_session_check
107 | *
108 | * gets a session value and optionally resets a new value or timeout
109 | * if session doesn't exist or timed out, then returns false, else returns value of session
110 | * @name (string) Name of session
111 | * @value (string) value of session
112 | * @timeoue (string) optional timeout of session
113 | * @return true
114 | */
115 | function fsl_session_check($name,$value = NULL,$timeout = NULL){
116 | if ((empty($_SESSION[$name] )) || ( (!empty( $_SESSION[$name.'_timeout'])) && (time() > $_SESSION[$name.'_timeout'])) )
117 | {
118 | fsl_session_kill($name); //run kill session command
119 | return false;
120 | }
121 | else
122 | {
123 | if(!empty($value)) $_SESSION[$name] = fsl_encrypt($value);
124 | if(!empty($timeout)) $_SESSION[$name.'_timeout'] = $timeout;
125 | }
126 |
127 | return fsl_decrypt($_SESSION[$name] );
128 | }
129 |
130 | /*
131 | * fsl_session_kill
132 | *
133 | * kills a session and associated timeout
134 | * @name (string) Name of session
135 | * returns true
136 | */
137 |
138 | function fsl_session_kill($name){
139 | unset($_SESSION[''.$name.'']);
140 | unset($_SESSION[''.$name.'_timeout']);
141 | session_destroy();
142 | return true;
143 | }
144 |
145 | /*
146 | *
147 | * fsl_jwt_encode
148 | *
149 | * creates a JWT Token
150 | *
151 | * @array (array) Array to be encoded in JWT
152 | * @key (string) OPTIONAL encryption key to use. If not provided default
153 | * key specified with option('global_encryption_key', 'setyourkeyhere') config
154 | * @return (string)
155 | */
156 | function fsl_jwt_encode($array,$key)
157 | {
158 | return JWT::encode($array, $key);
159 | }
160 |
161 | /*
162 | *
163 | * fsl_jwt_decode
164 | *
165 | * Decodes and validates a JWT Token and key combination
166 | *
167 | * @token (string) JWT to be decoded
168 | * @key (string) OPTIONAL encryption key to use. If not provided default
169 | * key specified with option('global_encryption_key', 'setyourkeyhere') config
170 | * @return (array) or error if validations fails
171 | */
172 | function fsl_jwt_decode($token,$key)
173 | {
174 | return JWT::decode($token, $key);
175 | }
176 |
177 | /*
178 | *
179 | * get_tiny_url
180 | *
181 | * Generates a Tiny URL
182 | *
183 | * @url (string) url to be shortened
184 | * @return (string)
185 | */
186 | function fsl_get_tiny_url($url) {
187 | $ch = curl_init();
188 | $timeout = 5;
189 | curl_setopt($ch,CURLOPT_URL,'https://tinyurl.com/api-create.php?url='.$url);
190 | curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
191 | curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
192 | $data = curl_exec($ch);
193 | curl_close($ch);
194 |
195 | return preg_replace("/^http:/i", "https:", $data);
196 | }
197 |
198 |
199 | /*
200 | * fsl_gauth_check
201 | *
202 | * checks if glogin session is set to 1 if not returns false
203 | *
204 | * @string (string) String to be decrypted
205 | * @key (string) OPTIONAL encryption key to use. If not provided default
206 | * key specified with option('global_encryption_key', 'setyourkeyhere') config
207 | * @return (string)
208 | */
209 |
210 | function fsl_gauth_check(){
211 | if ($_SESSION['glogin'] == 1)
212 | {
213 | return true;
214 | }
215 | else
216 | {
217 | return false;
218 | }
219 | }
220 |
221 |
222 | /*
223 | * fsl_gauth_getauthurl
224 | *
225 | * generates the auth url to use on google login button
226 | *
227 | * @string (string) String to be decrypted
228 | * @key (string) OPTIONAL encryption key to use. If not provided default
229 | * key specified with option('global_encryption_key', 'setyourkeyhere') config
230 | * @return (string)
231 | */
232 | function fsl_gauth_getauthurl()
233 | {
234 |
235 | $gClient = new Google_Client();
236 | $gClient->setApplicationName('Login');
237 | $gClient->setClientId(option('clientId'));
238 | $gClient->setClientSecret(option('clientSecret'));
239 | $gClient->setRedirectUri(option('redirectURL'));
240 | // $gClient->setHd(option('hd'));
241 | $google_oauthV2 = new Google_Oauth2Service($gClient);
242 | $authUrl = $gClient->createAuthUrl();
243 | return $authUrl;
244 | }
245 |
246 | /*
247 | * fsl_gauth_gettoken
248 | *
249 | * verify token from gauth is valid. If it is, returns array of google parameters
250 | *
251 | * @string (string) String to be decrypted
252 | * @key (string) OPTIONAL encryption key to use. If not provided default
253 | * key specified with option('global_encryption_key', 'setyourkeyhere') config
254 | * @return (string)
255 | */
256 | function fsl_gauth_gettoken()
257 | {
258 | $gClient = new Google_Client();
259 | $gClient->setApplicationName('Login');
260 | $gClient->setClientId(option('clientId'));
261 | $gClient->setClientSecret(option('clientSecret'));
262 | $gClient->setRedirectUri(option('redirectURL'));
263 | // $gClient->setHd(option('hd'));
264 | $google_oauthV2 = new Google_Oauth2Service($gClient);
265 |
266 | //google auth first
267 | if(isset($_GET['code'])){
268 | $gClient->authenticate($_GET['code']);
269 | $_SESSION['token'] = $gClient->getAccessToken();
270 |
271 | header('Location: ' . filter_var($redirectURL, FILTER_SANITIZE_URL));
272 | }
273 |
274 | if (isset($_SESSION['token'])) {
275 | $gClient->setAccessToken($_SESSION['token']);
276 | }
277 | //Call Google API
278 |
279 | if ($gClient->getAccessToken()) {
280 | //Get user profile data from google
281 | $gpUserProfile = $google_oauthV2->userinfo->get();
282 |
283 | /* $gpUserData = array(
284 | 'oauth_provider'=> 'google',
285 | 'oauth_uid' => $gpUserProfile['id'],
286 | 'first_name' => $gpUserProfile['given_name'],
287 | 'last_name' => $gpUserProfile['family_name'],
288 | 'email' => $gpUserProfile['email'],
289 | 'gender' => $gpUserProfile['gender'],
290 | 'locale' => $gpUserProfile['locale'],
291 | 'picture' => $gpUserProfile['picture'],
292 | 'link' => $gpUserProfile['link']
293 | ); */
294 | // $userData = $user->checkUser($gpUserData);
295 | //$output = $gpUserProfile['given_name'];
296 | //$uemail = $gpUserProfile['email'];
297 | $_SESSION['glogin'] = 1;
298 |
299 | $uemail = substr(strrchr($uemail, "@"), 1);
300 | if ($uemail == "konghq.com"){
301 | header('Location: ' . option('base_uri') . 'home/');
302 | }else {
303 | header('Location: ' . option('base_uri') . 'logout/');
304 | }
305 | return $gpUserData;
306 |
307 | } else {
308 |
309 | header('Location: ' . option('base_uri') . 'gauth/login/');
310 | }
311 | }
312 |
313 | /*
314 | * fsl_gauth_logout
315 | *
316 | * unsets google token and returns to base URL or URL of choice
317 | *
318 | * @string (string) String to be decrypted
319 | * @key (string) OPTIONAL encryption key to use. If not provided default
320 | * key specified with option('global_encryption_key', 'setyourkeyhere') config
321 | * @return (string)
322 | */
323 |
324 | /*
325 | *
326 | * fsl_hash_create
327 | *
328 | * creates a one way sha256 hash. Good for storing passwords, keys, and other data
329 | * elements where you do not need to unencrypt
330 | *
331 | * @string (string) data to be hashed
332 | * @return (string)
333 | */
334 | function fsl_hash_create($string)
335 | {
336 | return Password::create_hash($string);
337 | }
338 |
339 | /*
340 | *
341 | * fsl_hash_validate
342 | *
343 | * verify that a string matches a stored hashed version of the string
344 | *
345 | * @string (string) data to be validated
346 | * @good_hash (string) hash to be compared against
347 | * @return (boolean)
348 | */
349 | function fsl_hash_validate($string,$good_hash)
350 | {
351 | return Password::validate_password($string, $good_hash);
352 | }
353 |
354 |
355 | /*
356 | *
357 | * fsl_curl
358 | *
359 | * make an external http call. helpful when calling external api's
360 | *
361 | * @url: url of api
362 | * @method: action of request. Options include GET POST PUT DELETE
363 | * @datatype: expected data either XML or JSON supported. Otherwise defaults to *
364 | * @urlparams: url parameters (query string)
365 | * @postdata: array of data to submit
366 | * @authtype: authentication if needed BASIC or TOKEN (bearer token)
367 | * @$authuser: basic auth user
368 | * @$authpassword: basic auth password
369 | * @$authtoken: bearer token
370 | * @$customheader: ARRAY of custom headers
371 | * output: return array(http response code, curl info, response);
372 | */
373 |
374 | function fsl_curl($url, $method = "GET", $datatype = NULL, $urlparams = NULL, $postdata = NULL, $authtype = NULL, $authuser = NULL, $authpassword = NULL, $authtoken = NULL, $customheader = NULL ) {
375 | ini_set("default_socket_timeout", 10);
376 | if ($urlparams != NULL) {
377 | $url .= '?' . $urlparams;
378 | }
379 |
380 |
381 | //set user agent
382 | $headers = array('User-Agent: Fresh Squeezed Limonade (https://github.com/yesinteractive/fsl)');
383 |
384 | $ch = curl_init();
385 | curl_setopt($ch, CURLOPT_URL, $url);
386 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
387 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 'FALSE');
388 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 'FALSE');
389 | curl_setopt($ch, CURLOPT_TIMEOUT, 45); //timeout in seconds
390 |
391 | //data type
392 | if ($datatype == "XML") {
393 | array_push($headers,'Content-Type: application/xml');
394 | }else if ($datatype == "JSON") {
395 | array_push($headers,'Content-Type: application/json');
396 | }
397 | else if ($datatype == "FORM") {
398 | array_push($headers,'Content-Type: application/x-www-form-urlencoded');
399 | }else {
400 | array_push($headers,'Content-Type: */*');
401 | }
402 |
403 | //method
404 | if ($method == "POST") {
405 | //need to post the values?
406 | curl_setopt($ch, CURLOPT_POST, true);
407 | //fields which will be posted.
408 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
409 | } else if ($method == "PUT") {
410 | curl_setopt($ch, CURLOPT_PUT, true);
411 | } else if ($method == "DELETE") {
412 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
413 | } else{
414 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
415 | }
416 |
417 | //auth
418 | if ($authtype == "BASIC") {
419 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
420 | curl_setopt($ch, CURLOPT_USERPWD, "$authuser:$authpassword");
421 | } else if ($authtype == "TOKEN") {
422 | array_push($headers,'Authorization: Bearer ' . $authtoken);
423 | } else{
424 | //no auth
425 | }
426 |
427 | //merge headeer arrays if customheader set and set headers
428 | if ($customheader == NULL){
429 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
430 | } else {
431 | curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($headers,$customheader));
432 | }
433 |
434 | $output = curl_exec($ch);
435 | $info = curl_getinfo($ch);
436 | $code = $info['http_code'];
437 | curl_close($ch);
438 |
439 | return $ret = array($code, $info, $output);
440 | }
441 |
442 |
443 | ?>
--------------------------------------------------------------------------------
/lib/limonade/public/css/screen.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/lib/limonade/public/css/screen.css
--------------------------------------------------------------------------------
/lib/limonade/public/img/404.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/lib/limonade/public/img/404.gif
--------------------------------------------------------------------------------
/lib/limonade/public/img/fsl_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/lib/limonade/public/img/fsl_logo.png
--------------------------------------------------------------------------------
/lib/limonade/views/_debug.html.php:
--------------------------------------------------------------------------------
1 | ENV_PRODUCTION && option('debug')): ?>
2 |
3 | []
4 | (in line )
5 |
6 |
7 |
8 |
9 |
10 | Debug arguments
11 |
12 |
13 |
14 | Options
15 |
16 | [ ↑ ]
17 |
18 | Environment
19 |
20 | [ ↑ ]
21 |
22 | Backtrace
23 |
24 | [ ↑ ]
25 |
26 |
36 |
37 |
--------------------------------------------------------------------------------
/lib/limonade/views/_notices.html.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
→ Notices and warnings
4 |
5 |
6 | - []
7 | -
8 | in
9 | line
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/lib/limonade/views/default_layout.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | FSL Micro Framework for PHP
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/lib/limonade/views/error.html.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/public/banner-fsl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/banner-fsl.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/favicon.ico
--------------------------------------------------------------------------------
/public/fsl.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/fsl.jpeg
--------------------------------------------------------------------------------
/public/fsl_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/fsl_logo.png
--------------------------------------------------------------------------------
/public/kongmap2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/kongmap2.png
--------------------------------------------------------------------------------
/public/kongmap3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/kongmap3.png
--------------------------------------------------------------------------------
/public/launchpage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/launchpage.png
--------------------------------------------------------------------------------
/public/soda_glass.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/soda_glass.jpg
--------------------------------------------------------------------------------
/public/soda_glass.thb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/public/soda_glass.thb.jpg
--------------------------------------------------------------------------------
/screenshots/kongmap-deck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/screenshots/kongmap-deck.png
--------------------------------------------------------------------------------
/screenshots/kongmap-endpoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/screenshots/kongmap-endpoint.png
--------------------------------------------------------------------------------
/screenshots/kongmap-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yesinteractive/kong-map/a2847d32445e67cce3e05fd621f8c571fe56bdf1/screenshots/kongmap-home.png
--------------------------------------------------------------------------------
/views/fsl_default_layout.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | KongMap - API Gateway Visualizer
12 |
13 |
14 |
15 |
16 |
24 |
25 |
26 |
54 |
55 |
56 |
57 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
86 |
87 |
88 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/views/mapview.php:
--------------------------------------------------------------------------------
1 |