1<?php 2 3/** 4 * This file is part of the FreeDSx SASL package. 5 * 6 * (c) Chad Sikorra <Chad.Sikorra@gmail.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace FreeDSx\Sasl\Encoder; 13 14use FreeDSx\Sasl\Exception\SaslEncodingException; 15use FreeDSx\Sasl\Message; 16use FreeDSx\Sasl\SaslContext; 17 18/** 19 * Responsible for encoding / decoding PLAIN messages. 20 * 21 * @author Chad Sikorra <Chad.Sikorra@gmail.com> 22 */ 23class PlainEncoder implements EncoderInterface 24{ 25 /** 26 * {@inheritDoc} 27 */ 28 public function encode(Message $message, SaslContext $context): string 29 { 30 if (!$message->has('authzid')) { 31 throw new SaslEncodingException('The PLAIN message must contain a authzid.'); 32 } 33 if (!$message->has('authcid')) { 34 throw new SaslEncodingException('The PLAIN message must contain a authzid.'); 35 } 36 if (!$message->has('password')) { 37 throw new SaslEncodingException('The PLAIN message must contain a password.'); 38 } 39 $authzid = $this->validate($message->get('authzid')); 40 $authcid = $this->validate($message->get('authcid')); 41 $password = $this->validate($message->get('password')); 42 43 return $authzid . "\x00" . $authcid . "\x00" . $password; 44 } 45 46 /** 47 * {@inheritDoc} 48 */ 49 public function decode(string $data, SaslContext $context): Message 50 { 51 if (preg_match('/^([^\x0]+)\x00([^\x0]+)\x00([^\x0]+)$/', $data, $matches) === 0) { 52 throw new SaslEncodingException('The PLAIN message data is malformed.'); 53 } 54 55 return new Message([ 56 'authzid' => $matches[1], 57 'authcid' => $matches[2], 58 'password' => $matches[3], 59 ]); 60 } 61 62 protected function validate(string $data): string 63 { 64 if (strpos($data,"\x00") !== false) { 65 throw new SaslEncodingException('PLAIN mechanism data cannot contain a null character.'); 66 } 67 68 return $data; 69 } 70} 71