diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index 3372572a..e6e2bae0 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -116,22 +116,25 @@ impl SpotifyId { /// /// [Spotify URI]: https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids pub fn from_uri(src: &str) -> Result { - // We expect the ID to be the last colon-delimited item in the URI. - let b = src.as_bytes(); - let id_i = b.len() - SpotifyId::SIZE_BASE62; - if b[id_i - 1] != b':' { + let src = src.strip_prefix("spotify:").ok_or(SpotifyIdError)?; + + if src.len() <= SpotifyId::SIZE_BASE62 { return Err(SpotifyIdError); } - let mut id = SpotifyId::from_base62(&src[id_i..])?; + let colon_index = src.len() - SpotifyId::SIZE_BASE62 - 1; - // Slice offset by 8 as we are skipping the "spotify:" prefix. - id.audio_type = src[8..id_i - 1].into(); + if src.as_bytes()[colon_index] != b':' { + return Err(SpotifyIdError); + } + + let mut id = SpotifyId::from_base62(&src[colon_index + 1..])?; + id.audio_type = src[..colon_index].into(); Ok(id) } - /// Returns the `SpotifyId` as a base16 (hex) encoded, `SpotifyId::SIZE_BASE62` (22) + /// Returns the `SpotifyId` as a base16 (hex) encoded, `SpotifyId::SIZE_BASE16` (32) /// character long `String`. pub fn to_base16(&self) -> String { to_base16(&self.to_raw(), &mut [0u8; SpotifyId::SIZE_BASE16]) @@ -305,7 +308,7 @@ mod tests { }, ]; - static CONV_INVALID: [ConversionCase; 2] = [ + static CONV_INVALID: [ConversionCase; 3] = [ ConversionCase { id: 0, kind: SpotifyAudioType::NonPlayable, @@ -330,6 +333,18 @@ mod tests { 154, 27, 28, 251, ], }, + ConversionCase { + id: 0, + kind: SpotifyAudioType::NonPlayable, + // Uri too short + uri: "spotify:azb:aRS48xBl0tH", + base16: "--------------------", + base62: "....................", + raw: &[ + // Invalid length. + 154, 27, 28, 251, + ], + }, ]; #[test]