Passed
Push — master ( 14cefc...1cb0a0 )
by Stefan
05:05 queued 25s
created

API::uglify()   D

Complexity

Conditions 9
Paths 12

Size

Total Lines 44
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 44
rs 4.909
c 0
b 0
f 0
cc 9
eloc 34
nc 12
nop 1
1
<?php
2
3
/*
4
 * ******************************************************************************
5
 * Copyright 2011-2018 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
namespace web\lib\admin;
13
14
use Exception;
15
16
require_once(dirname(dirname(dirname(dirname(__FILE__)))) . "/config/_config.php");
17
18
class API {
19
20
    const ERROR_API_DISABLED = 1;
21
    const ERROR_NO_APIKEY = 2;
22
    const ERROR_INVALID_APIKEY = 3;
23
    const ERROR_MISSING_PARAMETER = 4;
24
    const ERROR_INVALID_PARAMETER = 5;
25
    const ERROR_NO_ACTION = 6;
26
    const ERROR_INVALID_ACTION = 7;
27
    const ERROR_MALFORMED_REQUEST = 8;
28
    const ACTION_NEWINST_BY_REF = "NEWINST-BY-REF";
29
    const ACTION_NEWINST = "NEWINST";
30
    const ACTION_DELINST = "DELINST";
31
    const ACTION_ADMIN_LIST = "ADMIN-LIST";
32
    const ACTION_ADMIN_ADD = "ADMIN-ADD";
33
    const ACTION_ADMIN_DEL = "ADMIN-DEL";
34
    const ACTION_STATISTICS_INST = "STATISTICS-INST";
35
    const ACTION_NEWPROF_RADIUS = "NEWPROF-RADIUS";
36
    const ACTION_NEWPROF_SB = "NEWPROF-SB";
37
    const ACTION_ENDUSER_NEW = "ENDUSER-NEW";
38
    const ACTION_ENDUSER_DEACTIVATE = "ENDUSER-DEACTIVATE";
39
    const ACTION_ENDUSER_LIST = "ENDUSER-LIST";
40
    const ACTION_TOKEN_NEW = "TOKEN-NEW";
41
    const ACTION_TOKEN_REVOKE = "TOKEN-REVOKE";
42
    const ACTION_TOKEN_LIST = "TOKEN-LIST";
43
    const ACTION_CERT_LIST = "CERT-LIST";
44
    const ACTION_CERT_REVOKE = "CERT-REVOKE";
45
    const AUXATTRIB_ADMINID = "ATTRIB-ADMINID";
46
    const AUXATTRIB_EXTERNALID = "ATTRIB-EXTERNALID";
47
48
    /*
49
     * ACTIONS consists of a list of keywords, and associated REQuired and OPTional parameters
50
     * 
51
     */
52
    const ACTIONS = [
53
        # inst-level actions
54
        API::ACTION_NEWINST_BY_REF => [
55
            "REQ" => [API::AUXATTRIB_EXTERNALID,],
56
            "OPT" => ['general:geo_coordinates', 'general:logo_file', 'media:SSID', 'media:SSID_with_legacy', 'media:wired', 'media:remove_SSID', 'media:consortium_OI', 'media:force_proxy', 'support:email', 'support:info_file', 'support:phone', 'support:url'],
57
        ],
58
        API::ACTION_NEWINST => [
59
            "REQ" => [],
60
            "OPT" => ['general:instname', 'general:geo_coordinates', 'general:logo_file', 'media:SSID', 'media:SSID_with_legacy', 'media:wired', 'media:remove_SSID', 'media:consortium_OI', 'media:force_proxy', 'support:email', 'support:info_file', 'support:phone', 'support:url'],
61
        ],
62
        API::ACTION_DELINST => [
63
            "REQ" => [],
64
            "OPT" => []
65
        ],
66
        API::ACTION_ADMIN_LIST => [
67
            "REQ" => [],
68
            "OPT" => []
69
        ],
70
        API::ACTION_ADMIN_ADD => [
71
            "REQ" => [],
72
            "OPT" => []
73
        ],
74
        API::ACTION_ADMIN_DEL => [
75
            "REQ" => [],
76
            "OPT" => []
77
        ],
78
        API::ACTION_STATISTICS_INST => [
79
            "REQ" => [],
80
            "OPT" => []
81
        ],
82
        # RADIUS profile actions
83
        API::ACTION_NEWPROF_RADIUS => [
84
            "REQ" => [],
85
            "OPT" => []
86
        ],
87
        # Silverbullet profile actions
88
        API::ACTION_NEWPROF_SB => [
89
            "REQ" => [],
90
            "OPT" => []
91
        ],
92
        API::ACTION_ENDUSER_NEW => [
93
            "REQ" => [],
94
            "OPT" => []
95
        ],
96
        API::ACTION_ENDUSER_DEACTIVATE => [
97
            "REQ" => [],
98
            "OPT" => []
99
        ],
100
        API::ACTION_ENDUSER_LIST => [
101
            "REQ" => [],
102
            "OPT" => []
103
        ],
104
        API::ACTION_TOKEN_NEW => [
105
            "REQ" => [],
106
            "OPT" => []
107
        ],
108
        API::ACTION_TOKEN_REVOKE => [
109
            "REQ" => [],
110
            "OPT" => []
111
        ],
112
        API::ACTION_TOKEN_LIST => [
113
            "REQ" => [],
114
            "OPT" => []
115
        ],
116
        API::ACTION_CERT_LIST => [
117
            "REQ" => [],
118
            "OPT" => []
119
        ],
120
        API::ACTION_CERT_REVOKE => [
121
            "REQ" => [],
122
            "OPT" => []
123
        ],
124
    ];
125
126
    /**
127
     * Only leave attributes in the request which are related to the ACTION.
128
     * Also sanitise by enforcing LANG attribute in multi-lang attributes.
129
     * 
130
     * @param array $inputJson the incoming JSON request
131
     * @return array the scrubbed attributes
132
     */
133
    public function scrub($inputJson) {
134
        $optionInstance = \core\Options::instance();
135
        $parameters = [];
136
        $allPossibleAttribs = array_merge(API::ACTIONS[$inputJson['ACTION']]['REQ'], API::ACTIONS[$inputJson['ACTION']]['OPT']);
137
        foreach ($inputJson['PARAMETERS'] as $number => $oneIncomingParam) {
138
            // index has to be an integer
139
            if (!is_int($number)) {
140
                continue;
141
            }
142
            // is this multi-lingual, and not an AUX attrib? Then check for presence of LANG and CONTENT before considering to add
143
            if (!preg_match("/^ATTRIB-/", $oneIncomingParam['NAME'])) {
144
                $optionProperties = $optionInstance->optionType($oneIncomingParam['NAME']);
145
                if ($optionProperties["flag"] == "ML" && !array_key_exists("LANG", $oneIncomingParam)) {
146
                    continue;
147
                }
148
            }
149
            // do we actually have a value?
150
            if (!array_key_exists("VALUE", $oneIncomingParam)) {
151
                continue;
152
            }
153
            if (in_array($oneIncomingParam['NAME'], $allPossibleAttribs)) {
154
                $parameters[$number] = $oneIncomingParam;
155
            }
156
        }
157
        return $parameters;
158
    }
159
160
    /**
161
     * we are coercing the submitted JSON-style parameters into the same format
162
     * we use for the HTML POST user-interactively.
163
     * That's ugly, hence the function name.
164
     * 
165
     * @param array $parameters
166
     */
167
    public function uglify($parameters) {
168
        $coercedInline = [];
169
        $coercedFile = [];
170
        $optionObject = \core\Options::instance();
171
        $cat = new \core\CAT();
172
        $dir = $cat->createTemporaryDirectory('test');
173
        foreach ($parameters as $number => $oneAttrib) {
174
            $optionInfo = $optionObject->optionType($oneAttrib['NAME']);
175
            $basename = "S$number";
176
            $extension = "";
177
            switch ($optionInfo['type']) {
178
179
                case \core\Options::TYPECODE_COORDINATES:
180
                    $extension = \core\Options::TYPECODE_TEXT;
181
                    $coercedInline["option"][$basename] = $oneAttrib['NAME']."#";
182
                    $coercedInline["value"][$basename . "-" . $extension] = $oneAttrib['VALUE'];
183
                    break;
184
                case \core\Options::TYPECODE_TEXT:
185
                // fall-through: they all get the same treatment
186
                case \core\Options::TYPECODE_BOOLEAN:
187
                // fall-through: they all get the same treatment
188
                case \core\Options::TYPECODE_STRING:
189
                // fall-through: they all get the same treatment
190
                case \core\Options::TYPECODE_INTEGER:
191
                    $extension = $optionInfo['type'];
192
                    $coercedInline["option"][$basename] = $oneAttrib['NAME']."#";
193
                    $coercedInline["value"][$basename . "-" . $extension] = $oneAttrib['VALUE'];
194
                    if ($optionInfo['flag'] == "ML") {
195
                        $coercedInline["value"][$basename . "-lang"] = $oneAttrib['LANG'];
196
                    }
197
                    break;
198
                case \core\Options::TYPECODE_FILE:
199
                    // binary data is expected in base64 encoding. This is true
200
                    // also for PEM files!
201
                    $extension = $optionInfo['type'];
202
                    $coercedInline["option"][$basename] = $oneAttrib['NAME']."#";
203
                    file_put_contents($dir['dir']."/".$basename."-".$extension, base64_decode($oneAttrib['VALUE']));
204
                    $coercedFile["value"]['tmp_name'][$basename."-".$extension] = $dir['dir']."/".$basename."-".$extension;
205
                    break;
206
                default:
207
                    throw new Exception("We don't seem to know this type code!");
208
            }
209
        }
210
        return ["POST" => $coercedInline, "FILES" => $coercedFile];
211
    }
212
213
}
214