@@ -57,7 +57,7 @@ public static function create(string $url, string $method, string $issuer, strin
5757 * Create Query String Hash
5858 *
5959 * More details:
60- * https://developer .atlassian.com/static/connect/docs/latest/ concepts/understanding-jwt .html#creating-token
60+ * https://docs .atlassian.com/DAC/bitbucket/ concepts/qsh .html
6161 *
6262 * @param string $url URL of the request
6363 * @param string $method HTTP method
@@ -67,40 +67,37 @@ public static function create(string $url, string $method, string $issuer, strin
6767 public static function qsh ($ url , $ method )
6868 {
6969 $ method = strtoupper ($ method );
70- $ parts = parse_url ($ url );
7170
72- // Remove "/wiki" part from the path for the Confluence
73- // Really, I didn't find this part in the docs, but it works
74- $ path = str_replace ('/wiki ' , '' , $ parts ['path ' ]);
71+ $ parts = parse_url ($ url );
72+ $ path = $ parts ['path ' ];
7573
76- $ canonicalQuery = '' ;
74+ // The list of prefixes which must be removed from the path
75+ $ prefixes = ['/wiki ' ];
7776
78- if (!empty ($ parts ['query ' ])) {
79- $ query = $ parts ['query ' ];
80- $ queryParts = explode ('& ' , $ query );
81- $ queryArray = [];
77+ foreach ($ prefixes as $ prefix ) {
78+ $ path = preg_replace ('/^ ' . preg_quote ($ prefix , '/ ' ) . '/ ' , '' , $ path );
79+ }
8280
83- foreach ($ queryParts as $ queryPart ) {
84- $ pieces = explode ('= ' , $ queryPart );
85- $ key = array_shift ($ pieces );
86- $ key = rawurlencode ($ key );
87- $ value = substr ($ queryPart , strlen ($ key ) + 1 );
88- $ value = rawurlencode ($ value );
89- $ queryArray [$ key ][] = $ value ;
90- }
81+ // Parse a query into the map of parameters
82+ parse_str ($ parts ['query ' ], $ params );
9183
92- ksort ($ queryArray );
84+ // Parameters should be sorted alphabetically
85+ ksort ($ params );
9386
94- foreach ($ queryArray as $ key => $ pieceOfQuery ) {
95- $ pieceOfQuery = implode (', ' , $ pieceOfQuery );
96- $ canonicalQuery .= $ key . '= ' . $ pieceOfQuery . '& ' ;
97- }
87+ $ canonicalQuery = http_build_query (
88+ $ params ,
89+ null ,
90+ '& ' ,
91+ PHP_QUERY_RFC3986
92+ );
9893
99- $ canonicalQuery = rtrim ($ canonicalQuery , '& ' );
100- }
94+ $ parts = [
95+ strtoupper ($ method ),
96+ $ path ,
97+ $ canonicalQuery
98+ ];
10199
102- $ qshString = implode ('& ' , [$ method , $ path , $ canonicalQuery ]);
103- $ qsh = hash ('sha256 ' , $ qshString );
100+ $ qsh = hash ('sha256 ' , implode ('& ' , $ parts ));
104101
105102 return $ qsh ;
106103 }
0 commit comments