blob: 52255287219c3c20999f29ae607d52401efd4b51 [file] [log] [blame]
Timoney, Daniel (dt5972)324ee362017-02-15 10:37:53 -05001/**
2 * Copyright 2014 IBM Corp.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 **/
16
17var should = require("should");
18var sinon = require('sinon');
19var request = require('supertest');
20var http = require('http');
21var express = require('express');
22
23var fs = require('fs-extra');
24var path = require('path');
25var when = require('when');
26
27var app = express();
28var RED = require("../../red/red.js");
29var server = require("../../red/server.js");
30var nodes = require("../../red/nodes");
31
32describe("library", function() {
33 var userDir = path.join(__dirname,".testUserHome");
34 before(function(done) {
35 fs.remove(userDir,function(err) {
36 fs.mkdir(userDir,function() {
37 sinon.stub(nodes, 'load', function() {
38 return when.promise(function(resolve,reject){
39 resolve([]);
40 });
41 });
42 RED.init(http.createServer(function(req,res){app(req,res)}),
43 {userDir: userDir});
44 server.start().then(function () { done(); });
45 });
46 });
47 });
48
49 after(function(done) {
50 fs.remove(userDir,done);
51 server.stop();
52 nodes.load.restore();
53 });
54
55 afterEach(function(done) {
56 fs.remove(userDir,function(err) {
57 fs.mkdir(userDir,done);
58 });
59 });
60
61 describe("flows", function() {
62 it('returns empty result', function(done) {
63 request(RED.httpAdmin)
64 .get('/library/flows')
65 .expect(200)
66 .end(function(err,res) {
67 if (err) {
68 throw err;
69 }
70 res.body.should.not.have.property('f');
71 done();
72 });
73 });
74
75 it('returns 404 for non-existent entry', function(done) {
76 request(RED.httpAdmin)
77 .get('/library/flows/foo')
78 .expect(404)
79 .end(done);
80 });
81
82 it('can store and retrieve item', function(done) {
83 var flow = '[]';
84 request(RED.httpAdmin)
85 .post('/library/flows/foo')
86 .set('Content-Type', 'text/plain')
87 .send(flow)
88 .expect(204).end(function (err, res) {
89 if (err) {
90 throw err;
91 }
92 request(RED.httpAdmin)
93 .get('/library/flows/foo')
94 .expect(200)
95 .end(function(err,res) {
96 if (err) {
97 throw err;
98 }
99 res.text.should.equal(flow);
100 done();
101 });
102 });
103 });
104
105 it('lists a stored item', function(done) {
106 request(RED.httpAdmin)
107 .post('/library/flows/bar')
108 .expect(204)
109 .end(function () {
110 request(RED.httpAdmin)
111 .get('/library/flows')
112 .expect(200)
113 .end(function(err,res) {
114 if (err) {
115 throw err;
116 }
117 res.body.should.have.property('f');
118 should.deepEqual(res.body.f,['bar']);
119 done();
120 });
121 });
122 });
123
124 it('returns 403 for malicious access attempt', function(done) {
125 // without the userDir override the malicious url would be
126 // http://127.0.0.1:1880/library/flows/../../package to
127 // obtain package.json from the node-red root.
128 request(RED.httpAdmin)
129 .get('/library/flows/../../../../../package')
130 .expect(403)
131 .end(done);
132 });
133
134 it('returns 403 for malicious access attempt', function(done) {
135 // without the userDir override the malicious url would be
136 // http://127.0.0.1:1880/library/flows/../../package to
137 // obtain package.json from the node-red root.
138 request(RED.httpAdmin)
139 .post('/library/flows/../../../../../package')
140 .expect(403)
141 .end(done);
142 });
143
144 });
145
146 describe("type", function() {
147 before(function() {
148 RED.library.register('test');
149 });
150
151 it('returns empty result', function(done) {
152 request(RED.httpAdmin)
153 .get('/library/test')
154 .expect(200)
155 .end(function(err,res) {
156 if (err) {
157 throw err;
158 }
159 res.body.should.not.have.property('f');
160 done();
161 });
162 });
163
164 it('returns 404 for non-existent entry', function(done) {
165 request(RED.httpAdmin)
166 .get('/library/test/foo')
167 .expect(404)
168 .end(done);
169 });
170
171 it('can store and retrieve item', function(done) {
172 var flow = '[]';
173 request(RED.httpAdmin)
174 .post('/library/test/foo')
175 .set('Content-Type', 'text/plain')
176 .send(flow)
177 .expect(204).end(function (err, res) {
178 if (err) {
179 throw err;
180 }
181 request(RED.httpAdmin)
182 .get('/library/test/foo')
183 .expect(200)
184 .end(function(err,res) {
185 if (err) {
186 throw err;
187 }
188 res.text.should.equal(flow);
189 done();
190 });
191 });
192 });
193
194 it('lists a stored item', function(done) {
195 request(RED.httpAdmin)
196 .post('/library/test/bar')
197 .expect(204)
198 .end(function () {
199 request(RED.httpAdmin)
200 .get('/library/test')
201 .expect(200)
202 .end(function(err,res) {
203 if (err) {
204 throw err;
205 }
206 should.deepEqual(res.body,[{ fn: 'bar'}]);
207 done();
208 });
209 });
210 });
211
212
213 it('returns 403 for malicious access attempt', function(done) {
214 request(RED.httpAdmin)
215 .get('/library/test/../../../../../../../../../../etc/passwd')
216 .expect(403)
217 .end(done);
218 });
219
220 it('returns 403 for malicious access attempt', function(done) {
221 request(RED.httpAdmin)
222 .get('/library/test/..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\etc\\passwd')
223 .expect(403)
224 .end(done);
225 });
226
227 it('returns 403 for malicious access attempt', function(done) {
228 request(RED.httpAdmin)
229 .post('/library/test/../../../../../../../../../../etc/passwd')
230 .set('Content-Type', 'text/plain')
231 .send('root:x:0:0:root:/root:/usr/bin/tclsh')
232 .expect(403)
233 .end(done);
234 });
235
236 });
237});