companion.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* global jest:false, test:false, expect:false, describe:false */
  2. const mockOauthState = require('../mockoauthstate')()
  3. const { version } = require('../../package.json')
  4. jest.mock('tus-js-client')
  5. jest.mock('purest')
  6. jest.mock('../../src/server/helpers/oauth-state', () => ({
  7. ...jest.requireActual('../../src/server/helpers/oauth-state'),
  8. ...mockOauthState,
  9. }))
  10. const nock = require('nock')
  11. const request = require('supertest')
  12. const tokenService = require('../../src/server/helpers/jwt')
  13. const { getServer } = require('../mockserver')
  14. // todo don't share server between tests. rewrite to not use env variables
  15. const authServer = getServer({ COMPANION_CLIENT_SOCKET_CONNECT_TIMEOUT: '0' })
  16. const authData = {
  17. dropbox: 'token value',
  18. box: 'token value',
  19. drive: 'token value',
  20. }
  21. const token = tokenService.generateEncryptedToken(authData, process.env.COMPANION_SECRET)
  22. const OAUTH_STATE = 'some-cool-nice-encrytpion'
  23. describe('validate upload data', () => {
  24. test('invalid upload protocol gets rejected', () => {
  25. return request(authServer)
  26. .post('/drive/get/DUMMY-FILE-ID')
  27. .set('uppy-auth-token', token)
  28. .set('Content-Type', 'application/json')
  29. .send({
  30. endpoint: 'http://url.myendpoint.com/files',
  31. protocol: 'tusInvalid',
  32. })
  33. .expect(400)
  34. .then((res) => expect(res.body.message).toBe('please specify a valid protocol'))
  35. })
  36. test('invalid upload fieldname gets rejected', () => {
  37. return request(authServer)
  38. .post('/drive/get/DUMMY-FILE-ID')
  39. .set('uppy-auth-token', token)
  40. .set('Content-Type', 'application/json')
  41. .send({
  42. endpoint: 'http://url.myendpoint.com/files',
  43. protocol: 'tus',
  44. fieldname: 390,
  45. })
  46. .expect(400)
  47. .then((res) => expect(res.body.message).toBe('fieldname must be a string'))
  48. })
  49. test('invalid upload metadata gets rejected', () => {
  50. return request(authServer)
  51. .post('/drive/get/DUMMY-FILE-ID')
  52. .set('uppy-auth-token', token)
  53. .set('Content-Type', 'application/json')
  54. .send({
  55. endpoint: 'http://url.myendpoint.com/files',
  56. protocol: 'tus',
  57. metadata: 'I am a string instead of object',
  58. })
  59. .expect(400)
  60. .then((res) => expect(res.body.message).toBe('metadata must be an object'))
  61. })
  62. test('invalid upload headers get rejected', () => {
  63. return request(authServer)
  64. .post('/drive/get/DUMMY-FILE-ID')
  65. .set('uppy-auth-token', token)
  66. .set('Content-Type', 'application/json')
  67. .send({
  68. endpoint: 'http://url.myendpoint.com/files',
  69. protocol: 'tus',
  70. headers: 'I am a string instead of object',
  71. })
  72. .expect(400)
  73. .then((res) => expect(res.body.message).toBe('headers must be an object'))
  74. })
  75. test('invalid upload HTTP Method gets rejected', () => {
  76. return request(authServer)
  77. .post('/drive/get/DUMMY-FILE-ID')
  78. .set('uppy-auth-token', token)
  79. .set('Content-Type', 'application/json')
  80. .send({
  81. endpoint: 'http://url.myendpoint.com/files',
  82. protocol: 'tus',
  83. httpMethod: 'DELETE',
  84. })
  85. .expect(400)
  86. .then((res) => expect(res.body.message).toBe('unsupported HTTP METHOD specified'))
  87. })
  88. test('valid upload data is allowed - tus', () => {
  89. return request(authServer)
  90. .post('/drive/get/DUMMY-FILE-ID')
  91. .set('uppy-auth-token', token)
  92. .set('Content-Type', 'application/json')
  93. .send({
  94. endpoint: 'http://url.myendpoint.com/files',
  95. protocol: 'tus',
  96. httpMethod: 'POST',
  97. headers: {
  98. customheader: 'header value',
  99. },
  100. metadata: {
  101. mymetadata: 'matadata value',
  102. },
  103. fieldname: 'uploadField',
  104. })
  105. .expect(200)
  106. })
  107. test('valid upload data is allowed - s3-multipart', () => {
  108. return request(authServer)
  109. .post('/drive/get/DUMMY-FILE-ID')
  110. .set('uppy-auth-token', token)
  111. .set('Content-Type', 'application/json')
  112. .send({
  113. endpoint: 'http://url.myendpoint.com/files',
  114. protocol: 's3-multipart',
  115. httpMethod: 'PUT',
  116. headers: {
  117. customheader: 'header value',
  118. },
  119. metadata: {
  120. mymetadata: 'matadata value',
  121. },
  122. fieldname: 'uploadField',
  123. })
  124. .expect(200)
  125. })
  126. })
  127. describe('handle main oauth redirect', () => {
  128. const serverWithMainOauth = getServer({
  129. COMPANION_OAUTH_DOMAIN: 'localhost:3040',
  130. })
  131. test('redirect to a valid uppy instance', () => {
  132. return request(serverWithMainOauth)
  133. .get(`/dropbox/redirect?state=${OAUTH_STATE}`)
  134. .set('uppy-auth-token', token)
  135. .expect(302)
  136. .expect('Location', `http://localhost:3020/connect/dropbox/callback?state=${OAUTH_STATE}`)
  137. })
  138. test('do not redirect to invalid uppy instances', () => {
  139. const state = 'state-with-invalid-instance-url' // see mock ../../src/server/helpers/oauth-state above
  140. return request(serverWithMainOauth)
  141. .get(`/dropbox/redirect?state=${state}`)
  142. .set('uppy-auth-token', token)
  143. .expect(400)
  144. })
  145. })
  146. it('periodically pings', (done) => {
  147. nock('http://localhost').post('/ping', (body) => (
  148. body.some === 'value'
  149. && body.version === version
  150. && typeof body.processId === 'string'
  151. )).reply(200, () => done())
  152. getServer({
  153. COMPANION_PERIODIC_PING_URLS: 'http://localhost/ping',
  154. COMPANION_PERIODIC_PING_STATIC_JSON_PAYLOAD: '{"some": "value"}',
  155. COMPANION_PERIODIC_PING_INTERVAL: '10',
  156. COMPANION_PERIODIC_PING_COUNT: '1',
  157. })
  158. }, 1000)
  159. it('respects allowLocalUrls', async () => {
  160. const server = getServer()
  161. const url = 'http://localhost/'
  162. let res
  163. res = await request(server)
  164. .post('/url/meta')
  165. .send({ url })
  166. .expect(400)
  167. expect(res.body).toEqual({ error: 'Invalid request body' })
  168. res = await request(server)
  169. .post('/url/get')
  170. .send({
  171. fileId: url,
  172. metadata: {},
  173. endpoint: 'http://url.myendpoint.com/files',
  174. protocol: 'tus',
  175. size: null,
  176. url,
  177. })
  178. .expect(400)
  179. expect(res.body).toEqual({ error: 'Invalid request body' })
  180. }, 1000)
  181. afterAll(() => {
  182. nock.cleanAll()
  183. nock.restore()
  184. })