Skip to content

Commit

Permalink
MDL-49103 badges: bake badges with iTXt chunk instead of tEXt
Browse files Browse the repository at this point in the history
The final OB 1.0 specification changed the baking badges method
from tEXt to iTXt. Besides, the iTXt chunk should be a signed
assertion or the raw JSON (instead of the assertion URL).
This has been changed in order to make Moodle OB compliant.

Yuliya Bozhko, thanks for the patch! :-)
  • Loading branch information
sarjona committed Feb 4, 2020
1 parent cb38ab1 commit f8d9b1e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
46 changes: 41 additions & 5 deletions badges/lib/bakerlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,23 +114,59 @@ public function check_chunks($type, $check) {
* @param string $value Currently an assertion URL that is added to an image metadata.
*
* @return string $result File content with a new chunk as a string. Can be used in file_put_contents() to write to a file.
* @throws \moodle_exception when unsupported chunk type is defined.
*/
public function add_chunks($type, $key, $value) {
if (strlen($key) > 79) {
debugging('Key is too big');
}

// tEXt Textual data.
// Keyword: 1-79 bytes (character string)
// Null separator: 1 byte
// Text: n bytes (character string)
$data = $key . "\0" . $value;
$dataparts = [];
if ($type === 'iTXt') {
// International textual data (iTXt).
// Keyword: 1-79 bytes (character string).
$dataparts[] = $key;
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Compression flag: 1 byte
// A value of 0 means no compression.
$dataparts[] = "\x00";
// Compression method: 1 byte
// If compression is disabled, the method should also be 0.
$dataparts[] = "\x00";
// Language tag: 0 or more bytes (character string)
// When there is no language specified leave empty.

// Null separator: 1 byte.
$dataparts[] = "\x00";
// Translated keyword: 0 or more bytes
// When there is no translation specified, leave empty.

// Null separator: 1 byte.
$dataparts[] = "\x00";
// Text: 0 or more bytes.
$dataparts[] = $value;
} else if ($type === 'tEXt') {
// Textual data (tEXt).
// Keyword: 1-79 bytes (character string).
$dataparts[] = $key;
// Null separator: 1 byte.
$dataparts[] = "\0";
// Text: n bytes (character string).
$dataparts[] = $value;
} else {
throw new \moodle_exception('Unsupported chunk type: ' . $type);
}

$data = implode($dataparts);

$crc = pack("N", crc32($type . $data));
$len = pack("N", strlen($data));

// Chunk format: length + type + data + CRC.
// CRC is a CRC-32 computed over the chunk type and chunk data.
$newchunk = $len . $type . $data . $crc;
$this->_chunks[$type] = $data;

$result = substr($this->_contents, 0, $this->_size - 12)
. $newchunk
Expand Down
11 changes: 7 additions & 4 deletions lib/badgeslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,10 +503,13 @@ function badges_bake($hash, $badgeid, $userid = 0, $pathhash = false) {
$contents = $file->get_content();

$filehandler = new PNG_MetaDataHandler($contents);
$assertion = new moodle_url('/badges/assertion.php', array('b' => $hash));
if ($filehandler->check_chunks("tEXt", "openbadges")) {
// Add assertion URL tExt chunk.
$newcontents = $filehandler->add_chunks("tEXt", "openbadges", $assertion->out(false));
// For now, the site backpack OB version will be used as default.
$obversion = badges_open_badges_backpack_api();
$assertion = new core_badges_assertion($hash, $obversion);
$assertionjson = json_encode($assertion->get_badge_assertion());
if ($filehandler->check_chunks("iTXt", "openbadges")) {
// Add assertion URL iTXt chunk.
$newcontents = $filehandler->add_chunks("iTXt", "openbadges", $assertionjson);
$fileinfo = array(
'contextid' => $user_context->id,
'component' => 'badges',
Expand Down

0 comments on commit f8d9b1e

Please sign in to comment.