PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
← All changes | app/Models/Attachment.php +57 -5 2.2.1 → 2.4.5 View file →
@@ -41,11 +41,10 @@
41 41 });
42 42 }
43 43
44 44 /**
45 - * Delete a collection of attachments — physical files first, then DB records.
46 - * Handles local files and fires the remote-driver hook for cloud-stored files.
47 - * Optionally removes the ticket upload directory after files are purged.
45 + * Delete the stored files for these attachments (local, or via the remote
46 + * driver hook). DB rows are left to the caller.
48 47 *
49 48 * @param \FluentSupport\Framework\Database\Orm\Collection|array $attachments
50 49 * @param int|null $ticketId When provided, removes the ticket_{id} upload directory.
51 50 */
@@ -82,15 +81,68 @@
82 81 return Helper::safeUnserialize($settings);
83 82 }
84 83
85 84 /**
86 - * Accessor to get dynamic full_name attribute
85 + * Signed download URL.
86 + *
87 87 * @return string
88 88 */
89 89 public function getSecureUrlAttribute()
90 90 {
91 + return $this->signedUrl(self::signedUrlExpiry());
92 + }
93 +
94 + /**
95 + * Download URL valid until $expires.
96 + *
97 + * @param int $expires Unix timestamp.
98 + * @return string
99 + */
100 + public function signedUrl($expires)
101 + {
91 102 return add_query_arg([
92 103 'fst_file' => $this->file_hash,
93 - 'secure_sign' => hash_hmac('sha256', $this->id . '|' . gmdate('YmdH'), wp_salt('secure_auth'))
104 + 'expires' => (int) $expires,
105 + 'secure_sign' => self::signature($this->id, (int) $expires)
94 106 ], site_url('/index.php'));
107 + }
108 +
109 + /**
110 + * Expiry for a newly signed URL. Rounded to a TTL boundary so the URL stays
111 + * the same for a while (browser caching), and always at least one TTL ahead.
112 + * A URL signed just before a boundary used to die within seconds.
113 + *
114 + * @return int Unix timestamp.
115 + */
116 + public static function signedUrlExpiry()
117 + {
118 + $ttl = max(MINUTE_IN_SECONDS * 5, (int) apply_filters('fluent_support/attachment_signed_url_ttl', HOUR_IN_SECONDS));
119 +
120 + return (intdiv(time(), $ttl) + 2) * $ttl;
121 + }
122 +
123 + /**
124 + * Signature for an expiring URL. The 'v2|' prefix keeps it apart from legacy
125 + * signatures: those signed "id|YmdH", and without the prefix an old hourly
126 + * signature would pass as one that expires in 2034 (2026100614 read as a timestamp).
127 + *
128 + * @param int $attachmentId
129 + * @param int $expires Unix timestamp.
130 + * @return string
131 + */
132 + public static function signature($attachmentId, $expires)
133 + {
134 + return hash_hmac('sha256', 'v2|' . $attachmentId . '|' . (int) $expires, wp_salt('secure_auth'));
135 + }
136 +
137 + /**
138 + * Signature of a pre-2.4.1 URL, valid for one UTC hour.
139 + *
140 + * @param int $attachmentId
141 + * @param string $hourWindow gmdate('YmdH')
142 + * @return string
143 + */
144 + public static function legacySignature($attachmentId, $hourWindow)
145 + {
146 + return hash_hmac('sha256', $attachmentId . '|' . $hourWindow, wp_salt('secure_auth'));
95 147 }
96 148 }