companion.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. const authServer = getServer()
  15. const authData = {
  16. dropbox: 'token value',
  17. box: 'token value',
  18. drive: 'token value',
  19. }
  20. const token = tokenService.generateEncryptedToken(authData, process.env.COMPANION_SECRET)
  21. const OAUTH_STATE = 'some-cool-nice-encrytpion'
  22. describe('validate upload data', () => {
  23. test('invalid upload protocol gets rejected', () => {
  24. return request(authServer)
  25. .post('/drive/get/DUMMY-FILE-ID')
  26. .set('uppy-auth-token', token)
  27. .set('Content-Type', 'application/json')
  28. .send({
  29. endpoint: 'http://url.myendpoint.com/files',
  30. protocol: 'tusInvalid',
  31. })
  32. .expect(400)
  33. .then((res) => expect(res.body.message).toBe('unsupported protocol specified'))
  34. })
  35. test('invalid upload fieldname gets rejected', () => {
  36. return request(authServer)
  37. .post('/drive/get/DUMMY-FILE-ID')
  38. .set('uppy-auth-token', token)
  39. .set('Content-Type', 'application/json')
  40. .send({
  41. endpoint: 'http://url.myendpoint.com/files',
  42. protocol: 'tus',
  43. fieldname: 390,
  44. })
  45. .expect(400)
  46. .then((res) => expect(res.body.message).toBe('fieldname must be a string'))
  47. })
  48. test('invalid upload metadata gets rejected', () => {
  49. return request(authServer)
  50. .post('/drive/get/DUMMY-FILE-ID')
  51. .set('uppy-auth-token', token)
  52. .set('Content-Type', 'application/json')
  53. .send({
  54. endpoint: 'http://url.myendpoint.com/files',
  55. protocol: 'tus',
  56. metadata: 'I am a string instead of object',
  57. })
  58. .expect(400)
  59. .then((res) => expect(res.body.message).toBe('metadata must be an object'))
  60. })
  61. test('invalid upload headers get rejected', () => {
  62. return request(authServer)
  63. .post('/drive/get/DUMMY-FILE-ID')
  64. .set('uppy-auth-token', token)
  65. .set('Content-Type', 'application/json')
  66. .send({
  67. endpoint: 'http://url.myendpoint.com/files',
  68. protocol: 'tus',
  69. headers: 'I am a string instead of object',
  70. })
  71. .expect(400)
  72. .then((res) => expect(res.body.message).toBe('headers must be an object'))
  73. })
  74. test('invalid upload HTTP Method gets rejected', () => {
  75. return request(authServer)
  76. .post('/drive/get/DUMMY-FILE-ID')
  77. .set('uppy-auth-token', token)
  78. .set('Content-Type', 'application/json')
  79. .send({
  80. endpoint: 'http://url.myendpoint.com/files',
  81. protocol: 'tus',
  82. httpMethod: 'DELETE',
  83. })
  84. .expect(400)
  85. .then((res) => expect(res.body.message).toBe('unsupported HTTP METHOD specified'))
  86. })
  87. test('valid upload data is allowed - tus', () => {
  88. return request(authServer)
  89. .post('/drive/get/DUMMY-FILE-ID')
  90. .set('uppy-auth-token', token)
  91. .set('Content-Type', 'application/json')
  92. .send({
  93. endpoint: 'http://url.myendpoint.com/files',
  94. protocol: 'tus',
  95. httpMethod: 'POST',
  96. headers: {
  97. customheader: 'header value',
  98. },
  99. metadata: {
  100. mymetadata: 'matadata value',
  101. },
  102. fieldname: 'uploadField',
  103. })
  104. .expect(200)
  105. })
  106. test('valid upload data is allowed - s3-multipart', () => {
  107. return request(authServer)
  108. .post('/drive/get/DUMMY-FILE-ID')
  109. .set('uppy-auth-token', token)
  110. .set('Content-Type', 'application/json')
  111. .send({
  112. endpoint: 'http://url.myendpoint.com/files',
  113. protocol: 's3-multipart',
  114. httpMethod: 'PUT',
  115. headers: {
  116. customheader: 'header value',
  117. },
  118. metadata: {
  119. mymetadata: 'matadata value',
  120. },
  121. fieldname: 'uploadField',
  122. })
  123. .expect(200)
  124. })
  125. })
  126. describe('handle main oauth redirect', () => {
  127. const serverWithMainOauth = getServer({
  128. COMPANION_OAUTH_DOMAIN: 'localhost:3040',
  129. })
  130. test('redirect to a valid uppy instance', () => {
  131. return request(serverWithMainOauth)
  132. .get(`/dropbox/redirect?state=${OAUTH_STATE}`)
  133. .set('uppy-auth-token', token)
  134. .expect(302)
  135. .expect('Location', `http://localhost:3020/connect/dropbox/callback?state=${OAUTH_STATE}`)
  136. })
  137. test('do not redirect to invalid uppy instances', () => {
  138. const state = 'state-with-invalid-instance-url' // see mock ../../src/server/helpers/oauth-state above
  139. return request(serverWithMainOauth)
  140. .get(`/dropbox/redirect?state=${state}`)
  141. .set('uppy-auth-token', token)
  142. .expect(400)
  143. })
  144. })
  145. it('periodically pings', (done) => {
  146. nock('http://localhost').post('/ping', (body) => (
  147. body.some === 'value'
  148. && body.version === version
  149. && typeof body.processId === 'string'
  150. )).reply(200, () => done())
  151. getServer({
  152. COMPANION_PERIODIC_PING_URLS: 'http://localhost/ping',
  153. COMPANION_PERIODIC_PING_STATIC_JSON_PAYLOAD: '{"some": "value"}',
  154. COMPANION_PERIODIC_PING_INTERVAL: '10',
  155. COMPANION_PERIODIC_PING_COUNT: '1',
  156. })
  157. }, 1000)
  158. afterAll(() => {
  159. nock.cleanAll()
  160. nock.restore()
  161. })