@@ -244,6 +244,7 @@ const { t } = useI18n()
244244const message = useMessage ()
245245const dialog = useDialog ()
246246const { $s3Client } = useNuxtApp ()
247+ const { credentials, permanentCredentials } = useAuth ()
247248
248249const props = defineProps <{
249250 bucketName: string
@@ -287,114 +288,127 @@ const openDrawer = async (_bucket: string, key: string) => {
287288 message .error (t (' Failed to fetch object info' ))
288289 }
289290}
290- // 有效期输入(天数、小时、分钟)
291+ // Expiration input (days, hours, minutes)
291292const expirationDays = ref <number >(0 )
292293const expirationHours = ref <number >(0 )
293294const expirationMinutes = ref <number >(0 )
294295const expirationError = ref <string >(' ' )
295296const totalExpirationSeconds = ref <number >(0 )
296297const isExpirationValid = ref <boolean >(false )
297298
298- // 一周的秒数
299+ // Seconds in a week
299300const ONE_WEEK_SECONDS = 7 * 24 * 60 * 60 // 604800
300301
301- // 计算总时长(秒数)
302+ // Calculate total duration (seconds)
302303const calculateTotalSeconds = (days : number , hours : number , minutes : number ): number => {
303304 return days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60
304305}
305306
306- // 验证有效期输入
307+ // Format duration display
308+ const formatDuration = (seconds : number ): string => {
309+ if (seconds === 0 ) return ' '
310+
311+ const days = Math .floor (seconds / (24 * 60 * 60 ))
312+ const hours = Math .floor ((seconds % (24 * 60 * 60 )) / (60 * 60 ))
313+ const minutes = Math .floor ((seconds % (60 * 60 )) / 60 )
314+
315+ const parts: string [] = []
316+ if (days > 0 ) parts .push (` ${days } ${t (' Days' )} ` )
317+ if (hours > 0 ) parts .push (` ${hours } ${t (' Hours' )} ` )
318+ if (minutes > 0 ) parts .push (` ${minutes } ${t (' Minutes' )} ` )
319+
320+ return parts .join (' ' )
321+ }
322+
323+ // Validate expiration input
307324const validateExpiration = (): boolean => {
308325 expirationError .value = ' '
309326
310- // 处理空值和非数字值,转换为0
327+ // Handle empty values and non-numeric values, convert to 0
311328 const days = Number (expirationDays .value ) || 0
312329 const hours = Number (expirationHours .value ) || 0
313330 const minutes = Number (expirationMinutes .value ) || 0
314331
315- // 检查是否为有效数字
332+ // Check if valid numbers
316333 if (isNaN (days ) || isNaN (hours ) || isNaN (minutes )) {
317334 return false
318335 }
319336
320- // 检查分钟范围 (0-59)
337+ // Check minutes range (0-59)
321338 if (minutes < 0 || minutes > 59 ) {
322339 expirationError .value = t (' Minutes must be between 0 and 59' )
323340 return false
324341 }
325342
326- // 检查小时范围
343+ // Check hours range
327344 if (hours < 0 ) {
328345 expirationError .value = t (' Hours must be between 0 and 23' )
329346 return false
330347 }
331348
332- // 如果天数大于0,小时不能超过23
349+ // If days > 0, hours cannot exceed 23
333350 if (days > 0 && hours > 23 ) {
334351 expirationError .value = t (' Hours must be between 0 and 23' )
335352 return false
336353 }
337354
338- // 如果天数为0,小时不能超过24
355+ // If days is 0, hours cannot exceed 24
339356 if (days === 0 && hours > 24 ) {
340357 expirationError .value = t (' Hours must be between 0 and 24 when days is 0' )
341358 return false
342359 }
343360
344- // 检查天数范围 (0-7)
361+ // Check days range (0-7)
345362 if (days < 0 || days > 7 ) {
346363 expirationError .value = t (' Days must be between 0 and 7' )
347364 return false
348365 }
349366
350- // 如果小时为24,自动转换为1天0小时(在计算时处理)
367+ // If hours is 24, automatically convert to 1 day 0 hours (handled in calculation)
351368 let finalDays = days
352369 let finalHours = hours
353370 if (hours === 24 && days === 0 ) {
354371 finalDays = 1
355372 finalHours = 0
356373 }
357374
358- // 计算总时长
375+ // Calculate total duration
359376 const totalSeconds = calculateTotalSeconds (finalDays , finalHours , minutes )
360377
361- // 检查总时长不能超过一周
378+ // Check total duration cannot exceed one week
362379 if (totalSeconds > ONE_WEEK_SECONDS ) {
363380 expirationError .value = t (' Total duration cannot exceed 7 days' )
364381 return false
365382 }
366383
367- // 检查至少有一个值大于0
384+ // Check at least one value is greater than 0
368385 if (totalSeconds === 0 ) {
369386 return false
370387 }
371388
389+ // Check if exceeds current session expiration
390+ if (credentials .value ?.Expiration && ! permanentCredentials .value ) {
391+ const expirationDate = new Date (credentials .value .Expiration )
392+ const now = new Date ()
393+ const remainingSeconds = Math .floor ((expirationDate .getTime () - now .getTime ()) / 1000 )
394+
395+ // If remaining time <= 0, session expired
396+ if (remainingSeconds <= 0 ) {
397+ expirationError .value = t (' Session expired, please login again' )
398+ return false
399+ }
400+ }
401+
372402 totalExpirationSeconds .value = totalSeconds
373403 return true
374404}
375405
376- // 验证并更新有效期
406+ // Validate and update expiration
377407const validateAndUpdateExpiration = () => {
378408 isExpirationValid .value = validateExpiration ()
379409}
380410
381- // 格式化时长显示
382- const formatDuration = (seconds : number ): string => {
383- if (seconds === 0 ) return ' '
384-
385- const days = Math .floor (seconds / (24 * 60 * 60 ))
386- const hours = Math .floor ((seconds % (24 * 60 * 60 )) / (60 * 60 ))
387- const minutes = Math .floor ((seconds % (60 * 60 )) / 60 )
388-
389- const parts: string [] = []
390- if (days > 0 ) parts .push (` ${days } ${t (' Days' )} ` )
391- if (hours > 0 ) parts .push (` ${hours } ${t (' Hours' )} ` )
392- if (minutes > 0 ) parts .push (` ${minutes } ${t (' Minutes' )} ` )
393-
394- return parts .join (' ' )
395- }
396-
397- // 生成临时链接
411+ // Generate temporary URL
398412const generateTemporaryUrl = async () => {
399413 if (! object .value ?.Key ) return
400414
@@ -404,7 +418,38 @@ const generateTemporaryUrl = async () => {
404418 }
405419
406420 try {
407- const url = await getSignedUrl (object .value .Key , totalExpirationSeconds .value )
421+ let url = ' '
422+ if (permanentCredentials .value ) {
423+ // If permanent credentials exist, use them to generate signed URL
424+ // Dynamic import to avoid large initial bundle, or since we are client-side, we can use AWS SDK directly
425+ // But here we need to create a new Client instance, because global $s3Client is STS-based (possibly)
426+ // Or we could reuse getSignedUrl logic in useObject, but need to pass different client
427+ const { S3Client, GetObjectCommand } = await import (' @aws-sdk/client-s3' )
428+ const { getSignedUrl : presignGetObject } = await import (' @aws-sdk/s3-request-presigner' )
429+
430+ const { $siteConfig } = useNuxtApp ()
431+ const siteConfig = $siteConfig as any
432+
433+ const tempClient = new S3Client ({
434+ endpoint: siteConfig .s3 .endpoint ,
435+ region: siteConfig .s3 .region || ' us-east-1' ,
436+ forcePathStyle: true ,
437+ credentials: {
438+ accessKeyId: permanentCredentials .value .AccessKeyId ! ,
439+ secretAccessKey: permanentCredentials .value .SecretAccessKey ! ,
440+ },
441+ })
442+
443+ const command = new GetObjectCommand ({
444+ Bucket: props .bucketName ,
445+ Key: object .value .Key ,
446+ })
447+
448+ url = await presignGetObject (tempClient , command , { expiresIn: totalExpirationSeconds .value })
449+ } else {
450+ url = await getSignedUrl (object .value .Key , totalExpirationSeconds .value )
451+ }
452+
408453 signedUrl .value = url
409454 message .success (t (' URL generated successfully' ))
410455 } catch (error : any ) {
@@ -416,7 +461,7 @@ const loadObjectInfo = async (key: string) => {
416461 const info = await getObjectInfo (key )
417462 object .value = info
418463 lockStatus .value = info ?.ObjectLockLegalHoldStatus === ' ON'
419- // 默认不生成分享链接,重置有效期输入
464+ // Default not to generate share link, reset expiration input
420465 expirationDays .value = 0
421466 expirationHours .value = 0
422467 expirationMinutes .value = 0
0 commit comments