Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/commands/app/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const {
const rtLib = require('@adobe/aio-lib-runtime')
const LogForwarding = require('../../lib/log-forwarding')
const { sendAppAssetsDeployedAuditLog, sendAppDeployAuditLog } = require('../../lib/audit-logger')
const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require('../../lib/auth-helper')
const { setRuntimeApiHostAndAuthHandler, getAccessToken, getTokenData } = require('../../lib/auth-helper')
const logActions = require('../../lib/log-actions')

const PRE_DEPLOY_EVENT_REG = 'pre-deploy-event-reg'
Expand Down Expand Up @@ -68,6 +68,8 @@ class Deploy extends BuildCommand {

if (cliDetails?.accessToken) {
try {
// store user id from token data for cdn deploy audit metadata
appInfo.auditUserId = getTokenData(cliDetails.accessToken)?.user_id
// send audit log at start (don't wait for deployment to finish)
await sendAppDeployAuditLog({
accessToken: cliDetails?.accessToken,
Expand Down Expand Up @@ -130,8 +132,7 @@ class Deploy extends BuildCommand {
// - break into smaller pieces deploy, allowing to first deploy all actions then all web assets
for (let i = 0; i < keys.length; ++i) {
const k = keys[i]
const v = setRuntimeApiHostAndAuthHandler(values[i])

const v = { auditUserId: appInfo.auditUserId, ...setRuntimeApiHostAndAuthHandler(values[i]) }
await this.deploySingleConfig({ name: k, config: v, originalConfig: values[i], flags, spinner })
if (cliDetails?.accessToken && v.app.hasFrontend && flags['web-assets']) {
const opItems = getFilesCountWithExtension(v.web.distProd)
Expand Down
23 changes: 22 additions & 1 deletion src/lib/auth-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License.
*/

const { getToken, context } = require('@adobe/aio-lib-ims')
const { getToken, context, getTokenData: getImsTokenData } = require('@adobe/aio-lib-ims')
const { CLI } = require('@adobe/aio-lib-ims/src/context')
const { getCliEnv } = require('@adobe/aio-lib-env')
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:auth-helper', { provider: 'debug' })
Expand Down Expand Up @@ -90,8 +90,29 @@ const setRuntimeApiHostAndAuthHandler = (_config) => {
}
}

/**
* Decodes a JWT token and returns its payload as a JavaScript object.
*
* @function getTokenData
* @param {string} token - The JWT token to decode
* @returns {object|null} The decoded payload of the JWT token or null if the token is invalid or cannot be decoded
*/
const getTokenData = (token) => {
if (typeof token !== 'string') {
aioLogger.error('Invalid token provided to getTokenData :: not a string')
return null
}
try {
return getImsTokenData(token)
} catch (e) {
aioLogger.error('Error decoding token payload in getTokenData ::', e)
return null
}
}

module.exports = {
getAccessToken,
getTokenData,
bearerAuthHandler,
setRuntimeApiHostAndAuthHandler
}
35 changes: 33 additions & 2 deletions test/commands/lib/auth-helper.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { getAccessToken, bearerAuthHandler, setRuntimeApiHostAndAuthHandler } = require('../../../src/lib/auth-helper')
const { getToken, context } = require('@adobe/aio-lib-ims')
const { getAccessToken, bearerAuthHandler, setRuntimeApiHostAndAuthHandler, getTokenData } = require('../../../src/lib/auth-helper')
const { getToken, context, getTokenData: getImsTokenData } = require('@adobe/aio-lib-ims')
const { CLI } = require('@adobe/aio-lib-ims/src/context')
const { getCliEnv } = require('@adobe/aio-lib-env')

Expand Down Expand Up @@ -57,6 +57,37 @@ describe('getAccessToken', () => {
})
})

describe('getTokenData', () => {
beforeEach(() => {
jest.clearAllMocks()
})

test('should call through to getImsTokenData to decode JWT token and return payload', () => {
getImsTokenData.mockReturnValue({ user_id: '12345', name: 'Test User' })
// Example JWT token with payload: {"user_id":"12345","name":"Test User"}
const exampleToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzNDUiLCJuYW1lIjoiVGVzdCBVc2VyIn0.sflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
const result = getTokenData(exampleToken)
expect(result).toEqual({ user_id: '12345', name: 'Test User' })
})
test('should return null for invalid token', () => {
getImsTokenData.mockImplementation(() => { throw new Error('Invalid token') })
const invalidToken = 'invalid.token.string'
const result = getTokenData(invalidToken)
expect(result).toBeNull()
})
test('should return null for malformed token', () => {
getImsTokenData.mockImplementation(() => { throw new Error('Malformed token') })
const malformedToken = 'malformedtoken'
const result = getTokenData(malformedToken)
expect(result).toBeNull()
})
test('should return null for non-string token', () => {
const nonStringToken = 12345
const result = getTokenData(nonStringToken)
expect(result).toBeNull()
})
})

describe('bearerAuthHandler', () => {
beforeEach(() => {
jest.clearAllMocks()
Expand Down
Loading