/** * For initializing members of the class. * * @param array $args misc. arguments * * @return boolean true */ function prepare($args) { parent::prepare($args); if (!$this->isPost()) { throw new ClientException(_('POST only'), 405); } $this->checkSessionToken(); $this->url = $this->trimmed('url'); if (empty($this->url)) { throw new ClientException(_('URL is required.'), 400); } if (!common_valid_http_url($this->url)) { throw new ClientException(_('Invalid URL.'), 400); } try { // processNew will first try to fetch a locally stored File entry $f = File::processNew($this->url); } catch (ServerException $e) { $f = null; } // How about now? if ($f instanceof File) { // FIXME: Use some File metadata Event instead $this->oembed = File_oembed::getKV('file_id', $f->id); if ($this->oembed instanceof File_oembed) { $this->title = $this->oembed->title; } $this->thumbnail = File_thumbnail::getKV('file_id', $f->id); } return true; }
function onEndFindMentions(Profile $sender, $text, &$mentions) { $matches = array(); preg_match_all('/(?:^|\\s+)@([A-Za-z0-9_:\\-\\.\\/%]+)\\b/', $text, $atmatches, PREG_OFFSET_CAPTURE); foreach ($atmatches[1] as $match) { $url = $match[0]; if (!common_valid_http_url($url)) { $url = 'http://' . $url; } if (common_valid_http_url($url)) { $mentioned = Mention_url_profile::fromUrl($url); $text = mb_strlen($mentioned->nickname) <= mb_strlen($match[0]) ? $mentioned->nickname : $match[0]; } if ($mentioned instanceof Profile) { $matches[$match[1]] = array('mentioned' => array($mentioned), 'type' => 'mention', 'text' => $text, 'position' => $match[1], 'length' => mb_strlen($match[0]), 'url' => $mentioned->profileurl); } } foreach ($mentions as $i => $other) { // If we share a common prefix with a local user, override it! $pos = $other['position']; if (isset($matches[$pos])) { $mentions[$i] = $matches[$pos]; unset($matches[$pos]); } } foreach ($matches as $mention) { $mentions[] = $mention; } return true; }
function handle($args) { // Trigger short error responses; not a human-readable web page. StatusNet::setApi(true); // We're not a general oEmbed proxy service; limit to valid sessions. $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { // TRANS: Client error displayed when the session token does not match or is not given. $this->clientError(_m('There was a problem with your session token. ' . 'Try again, please.')); } $format = $this->arg('format'); if ($format && $format != 'json') { // TRANS: Client exception thrown when requesting a different format than JSON. throw new ClientException(_m('Invalid format; only JSON supported.')); } $url = $this->arg('url'); if (!common_valid_http_url($url)) { // TRANS: Client exception thrown when not providing a valid URL. throw new ClientException(_m('Invalid URL.')); } $params = array(); if ($this->arg('maxwidth')) { $params['maxwidth'] = $this->arg('maxwidth'); } if ($this->arg('maxheight')) { $params['maxheight'] = $this->arg('maxheight'); } $data = oEmbedHelper::getObject($url, $params); $this->init_document('json'); print json_encode($data); }
protected function validateFeedUrl($url) { if (common_valid_http_url($url)) { return $url; } else { $this->clientError(_m("Invalid feed URL.")); } }
protected function validateFeedUrl($url) { if (common_valid_http_url($url)) { return $url; } else { // TRANS: Client error displayed when entering an invalid URL for a feed. // TRANS: %s is the invalid feed URL. $this->clientError(sprintf(_m("Invalid feed URL: %s."), $url)); } }
protected function doPost() { if (Event::handle('StartGroupSaveForm', array($this))) { $nickname = Nickname::normalize($this->trimmed('newnickname'), true); $fullname = $this->trimmed('fullname'); $homepage = $this->trimmed('homepage'); $description = $this->trimmed('description'); $location = $this->trimmed('location'); $private = $this->boolean('private'); $aliasstring = $this->trimmed('aliases'); if (!is_null($homepage) && strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Group create form validation error. throw new ClientException(_('Homepage is not a valid URL.')); } else { if (!is_null($fullname) && mb_strlen($fullname) > 255) { // TRANS: Group create form validation error. throw new ClientException(_('Full name is too long (maximum 255 characters).')); } else { if (User_group::descriptionTooLong($description)) { // TRANS: Group create form validation error. // TRANS: %d is the maximum number of allowed characters. throw new ClientException(sprintf(_m('Description is too long (maximum %d character).', 'Description is too long (maximum %d characters).', User_group::maxDescription()), User_group::maxDescription())); } else { if (!is_null($location) && mb_strlen($location) > 255) { // TRANS: Group create form validation error. throw new ClientException(_('Location is too long (maximum 255 characters).')); } } } } if (!empty($aliasstring)) { $aliases = array_map(array('Nickname', 'normalize'), array_unique(preg_split('/[\\s,]+/', $aliasstring))); } else { $aliases = array(); } if (count($aliases) > common_config('group', 'maxaliases')) { // TRANS: Group create form validation error. // TRANS: %d is the maximum number of allowed aliases. throw new ClientException(sprintf(_m('Too many aliases! Maximum %d allowed.', 'Too many aliases! Maximum %d allowed.', common_config('group', 'maxaliases')), common_config('group', 'maxaliases'))); } if ($private) { $force_scope = 1; $join_policy = User_group::JOIN_POLICY_MODERATE; } else { $force_scope = 0; $join_policy = User_group::JOIN_POLICY_OPEN; } // This is set up in parent->prepare and checked in self->prepare assert(!is_null($this->scoped)); $group = User_group::register(array('nickname' => $nickname, 'fullname' => $fullname, 'homepage' => $homepage, 'description' => $description, 'location' => $location, 'aliases' => $aliases, 'userid' => $this->scoped->id, 'join_policy' => $join_policy, 'force_scope' => $force_scope, 'local' => true)); $this->group = $group; Event::handle('EndGroupSaveForm', array($this)); common_redirect($group->homeUrl(), 303); } }
protected function saveObjectFromActivity(Activity $act, Notice $stored, array $options = array()) { assert($this->isMyActivity($act)); $stored->object_type = ActivityUtils::resolveUri($act->objects[0]->type); if (common_valid_http_url($act->objects[0]->link)) { $stored->url = $act->objects[0]->link; } // We don't have to do just about anything for a new, remote notice since the fields // are handled in the main Notice::saveActivity function. Such as content, attachments, // parent/conversation etc. // By returning true here instead of something that evaluates // to false, we show that we have processed everything properly. return true; }
/** * Take arguments for running * * @param array $args $_REQUEST args * * @return boolean success flag */ protected function prepare(array $args = array()) { parent::prepare($args); if ($this->format !== 'json') { $this->clientError('This method currently only serves JSON.', 415); } $this->url = urldecode($args['url']); if (empty($this->url)) { $this->clientError(_('No URL.'), 403); } if (!common_valid_http_url($this->url)) { $this->clientError(_('Invalid URL.'), 403); } return true; }
/** * Download and update given avatar image * * @param string $url * @throws Exception in various failure cases */ public function updateAvatar($url) { if (!common_valid_http_url($url)) { // TRANS: Server exception. %s is a URL. throw new ServerException(sprintf(_m('Invalid avatar URL %s.'), $url)); } if ($this->isGroup()) { $self = $this->localGroup(); } else { $self = $this->localProfile(); } if (!$self) { throw new ServerException(sprintf(_m('Tried to update avatar for unsaved remote profile %s.'), $this->uri)); } // @fixme this should be better encapsulated // ripped from oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); try { if (!copy($url, $temp_filename)) { // TRANS: Server exception. %s is a URL. throw new ServerException(sprintf(_m('Unable to fetch avatar from %s.'), $url)); } if ($this->isGroup()) { $id = $this->group_id; } else { $id = $this->profile_id; } // @fixme should we be using different ids? $imagefile = new ImageFile($id, $temp_filename); $filename = Avatar::filename($id, image_type_to_extension($imagefile->type), null, common_timestamp()); rename($temp_filename, Avatar::path($filename)); } catch (Exception $e) { unlink($temp_filename); throw $e; } // @fixme hardcoded chmod is lame, but seems to be necessary to // keep from accidentally saving images from command-line (queues) // that can't be read from web server, which causes hard-to-notice // problems later on: // // http://status.net/open-source/issues/2663 chmod(Avatar::path($filename), 0644); $self->setOriginal($filename); $orig = clone $this; $this->avatar = $url; $this->update($orig); }
function save_notice(&$req, &$consumer, &$token) { $version = $req->get_parameter('omb_version'); if ($version != OMB_VERSION_01) { $this->clientError(_('Unsupported OMB version'), 400); return false; } # First, check to see $listenee = $req->get_parameter('omb_listenee'); $remote_profile = Remote_profile::staticGet('uri', $listenee); if (!$remote_profile) { $this->clientError(_('Profile unknown'), 403); return false; } $sub = Subscription::staticGet('token', $token->key); if (!$sub) { $this->clientError(_('No such subscription'), 403); return false; } $content = $req->get_parameter('omb_notice_content'); $content_shortened = common_shorten_links($content); if (mb_strlen($content_shortened) > 140) { $this->clientError(_('Invalid notice content'), 400); return false; } $notice_uri = $req->get_parameter('omb_notice'); if (!Validate::uri($notice_uri) && !common_valid_tag($notice_uri)) { $this->clientError(_('Invalid notice uri'), 400); return false; } $notice_url = $req->get_parameter('omb_notice_url'); if ($notice_url && !common_valid_http_url($notice_url)) { $this->clientError(_('Invalid notice url'), 400); return false; } $notice = Notice::staticGet('uri', $notice_uri); if (!$notice) { $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri); if (is_string($notice)) { common_server_serror($notice, 500); return false; } common_broadcast_notice($notice, true); } return true; }
/** * Try to register a user * * Validates the input and tries to save a new user and profile * record. On success, shows an instructions page. * * @return void */ function tryRegister() { if (Event::handle('StartRegistrationTry', array($this))) { $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { // TRANS: Client error displayed when the session token does not match or is not given. $this->showForm(_('There was a problem with your session token. ' . 'Try again, please.')); return; } $nickname = $this->trimmed('nickname'); $email = $this->trimmed('email'); $fullname = $this->trimmed('fullname'); $homepage = $this->trimmed('homepage'); $bio = $this->trimmed('bio'); $location = $this->trimmed('location'); // We don't trim these... whitespace is OK in a password! $password = $this->arg('password'); $confirm = $this->arg('confirm'); // invitation code, if any $code = $this->trimmed('code'); if ($code) { $invite = Invitation::getKV($code); } if (common_config('site', 'inviteonly') && !($code && $invite)) { // TRANS: Client error displayed when trying to register to an invite-only site without an invitation. $this->clientError(_('Sorry, only invited people can register.')); } // Input scrubbing try { $nickname = Nickname::normalize($nickname, true); } catch (NicknameException $e) { $this->showForm($e->getMessage()); return; } $email = common_canonical_email($email); if (!$this->boolean('license')) { // TRANS: Form validation error displayed when trying to register without agreeing to the site license. $this->showForm(_('You cannot register if you do not ' . 'agree to the license.')); } else { if ($email && !Validate::email($email, common_config('email', 'check_domain'))) { // TRANS: Form validation error displayed when trying to register without a valid e-mail address. $this->showForm(_('Not a valid email address.')); } else { if ($this->emailExists($email)) { // TRANS: Form validation error displayed when trying to register with an already registered e-mail address. $this->showForm(_('Email address already exists.')); } else { if (!is_null($homepage) && strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Form validation error displayed when trying to register with an invalid homepage URL. $this->showForm(_('Homepage is not a valid URL.')); } else { if (!is_null($fullname) && mb_strlen($fullname) > 255) { // TRANS: Form validation error displayed when trying to register with a too long full name. $this->showForm(_('Full name is too long (maximum 255 characters).')); } else { if (Profile::bioTooLong($bio)) { // TRANS: Form validation error on registration page when providing too long a bio text. // TRANS: %d is the maximum number of characters for bio; used for plural. $this->showForm(sprintf(_m('Bio is too long (maximum %d character).', 'Bio is too long (maximum %d characters).', Profile::maxBio()), Profile::maxBio())); } else { if (!is_null($location) && mb_strlen($location) > 255) { // TRANS: Form validation error displayed when trying to register with a too long location. $this->showForm(_('Location is too long (maximum 255 characters).')); } else { if (strlen($password) < 6) { // TRANS: Form validation error displayed when trying to register with too short a password. $this->showForm(_('Password must be 6 or more characters.')); } else { if ($password != $confirm) { // TRANS: Form validation error displayed when trying to register with non-matching passwords. $this->showForm(_('Passwords do not match.')); } else { try { $user = User::register(array('nickname' => $nickname, 'password' => $password, 'email' => $email, 'fullname' => $fullname, 'homepage' => $homepage, 'bio' => $bio, 'location' => $location, 'code' => $code)); // success! if (!common_set_user($user)) { // TRANS: Server error displayed when saving fails during user registration. $this->serverError(_('Error setting user.')); } // this is a real login common_real_login(true); if ($this->boolean('rememberme')) { common_debug('Adding rememberme cookie for ' . $nickname); common_rememberme($user); } // Re-init language env in case it changed (not yet, but soon) common_init_language(); Event::handle('EndRegistrationTry', array($this)); $this->showSuccess(); } catch (Exception $e) { // TRANS: Form validation error displayed when trying to register with an invalid username or password. $this->showForm($e->getMessage()); } } } } } } } } } } } }
/** * Actually save the avatar we found locally. * * @param User $user * @param string $url to avatar URL * @todo merge wrapper funcs for this into common place for 1.0 core */ private function saveAvatar($user, $url) { if (!common_valid_http_url($url)) { throw new ServerException(sprintf(_m("Invalid avatar URL %s."), $url)); } // @fixme this should be better encapsulated // ripped from OStatus via oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); try { if (!copy($url, $temp_filename)) { throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url)); } $profile = $user->getProfile(); $id = $profile->id; // @fixme should we be using different ids? $imagefile = new ImageFile($id, $temp_filename); $filename = Avatar::filename($id, image_type_to_extension($imagefile->type), null, common_timestamp()); rename($temp_filename, Avatar::path($filename)); } catch (Exception $e) { unlink($temp_filename); throw $e; } $profile->setOriginal($filename); }
function oid_authenticate($openid_url, $returnto, $immediate = false) { if (!common_valid_http_url($openid_url)) { throw new ClientException(_m('No valid URL provided for OpenID.')); } $consumer = oid_consumer(); if (!$consumer) { // TRANS: OpenID plugin server error. throw new ServerException(_m('Cannot instantiate OpenID consumer object.')); } common_ensure_session(); $auth_request = $consumer->begin($openid_url); // Handle failure status return values. if (!$auth_request) { common_log(LOG_ERR, __METHOD__ . ": mystery fail contacting {$openid_url}"); // TRANS: OpenID plugin message. Given when an OpenID is not valid. throw new ServerException(_m('Not a valid OpenID.')); } else { if (Auth_OpenID::isFailure($auth_request)) { common_log(LOG_ERR, __METHOD__ . ": OpenID fail to {$openid_url}: {$auth_request->message}"); // TRANS: OpenID plugin server error. Given when the OpenID authentication request fails. // TRANS: %s is the failure message. throw new ServerException(sprintf(_m('OpenID failure: %s.'), $auth_request->message)); } } $sreg_request = Auth_OpenID_SRegRequest::build(array(), array('nickname', 'email', 'fullname', 'language', 'timezone', 'postcode', 'country')); if ($sreg_request) { $auth_request->addExtension($sreg_request); } $requiredTeam = common_config('openid', 'required_team'); if ($requiredTeam) { // LaunchPad OpenID extension $team_request = new Auth_OpenID_TeamsRequest(array($requiredTeam)); if ($team_request) { $auth_request->addExtension($team_request); } } $trust_root = common_root_url(true); $process_url = common_local_url($returnto); // Net::OpenID::Server as used on LiveJournal appears to incorrectly // reject POST requests for data submissions that OpenID 1.1 specs // as GET, although 2.0 allows them: // https://rt.cpan.org/Public/Bug/Display.html?id=42202 // // Our OpenID libraries would have switched in the redirect automatically // if it were detecting 1.1 compatibility mode, however the server is // advertising itself as 2.0-compatible, so we got switched to the POST. // // Since the GET should always work anyway, we'll just take out the // autosubmitter for now. // //if ($auth_request->shouldSendRedirect()) { $redirect_url = $auth_request->redirectURL($trust_root, $process_url, $immediate); if (Auth_OpenID::isFailure($redirect_url)) { // TRANS: OpenID plugin server error. Given when the OpenID authentication request cannot be redirected. // TRANS: %s is the failure message. throw new ServerException(sprintf(_m('Could not redirect to server: %s.'), $redirect_url->message)); } common_redirect($redirect_url, 303); /* } else { // Generate form markup and render it. $form_id = 'openid_message'; $form_html = $auth_request->formMarkup($trust_root, $process_url, $immediate, array('id' => $form_id)); // XXX: This is cheap, but things choke if we don't escape ampersands // in the HTML attributes $form_html = preg_replace('/&/', '&', $form_html); // Display an error if the form markup couldn't be generated; // otherwise, render the HTML. if (Auth_OpenID::isFailure($form_html)) { // TRANS: OpenID plugin server error if the form markup could not be generated. // TRANS: %s is the failure message. common_server_error(sprintf(_m('Could not create OpenID form: %s'), $form_html->message)); } else { $action = new AutosubmitAction(); // see below $action->form_html = $form_html; $action->form_id = $form_id; $action->prepare(array('action' => 'autosubmit')); $action->handle(array('action' => 'autosubmit')); } } */ }
/** * Handle the request * * @param array $args $_REQUEST data (unused) * * @return void */ protected function handle() { parent::handle(); $nickname = $this->trimmed('nickname'); $email = $this->trimmed('email'); $fullname = $this->trimmed('fullname'); $homepage = $this->trimmed('homepage'); $bio = $this->trimmed('bio'); $location = $this->trimmed('location'); // We don't trim these... whitespace is OK in a password! $password = $this->arg('password'); $confirm = $this->arg('confirm'); if (empty($this->code)) { common_ensure_session(); if (array_key_exists('invitecode', $_SESSION)) { $this->code = $_SESSION['invitecode']; } } if (common_config('site', 'inviteonly') && empty($this->code)) { // TRANS: Client error displayed when trying to register to an invite-only site without an invitation. $this->clientError(_('Sorry, only invited people can register.'), 401); } if (!empty($this->code)) { $this->invite = Invitation::getKV('code', $this->code); if (empty($this->invite)) { // TRANS: Client error displayed when trying to register to an invite-only site without a valid invitation. $this->clientError(_('Sorry, invalid invitation code.'), 401); } // Store this in case we need it common_ensure_session(); $_SESSION['invitecode'] = $this->code; } // Input scrubbing try { $nickname = Nickname::normalize($nickname, true); } catch (NicknameException $e) { // clientError handles Api exceptions with various formats and stuff $this->clientError($e->getMessage(), $e->getCode()); } $email = common_canonical_email($email); if ($email && !Validate::email($email, common_config('email', 'check_domain'))) { // TRANS: Form validation error displayed when trying to register without a valid e-mail address. $this->clientError(_('Not a valid email address.'), 400); } else { if ($this->emailExists($email)) { // TRANS: Form validation error displayed when trying to register with an already registered e-mail address. $this->clientError(_('Email address already exists.'), 400); } else { if (!is_null($homepage) && strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Form validation error displayed when trying to register with an invalid homepage URL. $this->clientError(_('Homepage is not a valid URL.'), 400); } else { if (!is_null($fullname) && mb_strlen($fullname) > 255) { // TRANS: Form validation error displayed when trying to register with a too long full name. $this->clientError(_('Full name is too long (maximum 255 characters).'), 400); } else { if (Profile::bioTooLong($bio)) { // TRANS: Form validation error on registration page when providing too long a bio text. // TRANS: %d is the maximum number of characters for bio; used for plural. $this->clientError(sprintf(_m('Bio is too long (maximum %d character).', 'Bio is too long (maximum %d characters).', Profile::maxBio()), Profile::maxBio()), 400); } else { if (!is_null($location) && mb_strlen($location) > 255) { // TRANS: Form validation error displayed when trying to register with a too long location. $this->clientError(_('Location is too long (maximum 255 characters).'), 400); } else { if (strlen($password) < 6) { // TRANS: Form validation error displayed when trying to register with too short a password. $this->clientError(_('Password must be 6 or more characters.'), 400); } else { if ($password != $confirm) { // TRANS: Form validation error displayed when trying to register with non-matching passwords. $this->clientError(_('Passwords do not match.'), 400); } else { // annoy spammers sleep(7); try { $user = User::register(array('nickname' => $nickname, 'password' => $password, 'email' => $email, 'fullname' => $fullname, 'homepage' => $homepage, 'bio' => $bio, 'location' => $location, 'code' => $this->code)); Event::handle('EndRegistrationTry', array($this)); $this->initDocument('json'); $this->showJsonObjects($this->twitterUserArray($user->getProfile())); $this->endDocument('json'); } catch (Exception $e) { $this->clientError($e->getMessage(), 400); } } } } } } } } } }
function remoteSubscription() { if (!$this->nickname) { $this->showForm(_('No such user.')); return; } $user = User::staticGet('nickname', $this->nickname); $this->profile_url = $this->trimmed('profile_url'); if (!$this->profile_url) { $this->showForm(_('No such user.')); return; } if (!common_valid_http_url($this->profile_url)) { $this->showForm(_('Invalid profile URL (bad format)')); return; } try { $service = new OMB_Service_Consumer($this->profile_url, common_root_url(), omb_oauth_datastore()); } catch (OMB_InvalidYadisException $e) { $this->showForm(_('Not a valid profile URL (no YADIS document or ' . 'invalid XRDS defined).')); return; } if ($service->getServiceURI(OAUTH_ENDPOINT_REQUEST) == common_local_url('requesttoken') || User::staticGet('uri', $service->getRemoteUserURI())) { $this->showForm(_('That’s a local profile! Login to subscribe.')); return; } try { $service->requestToken(); } catch (OMB_RemoteServiceException $e) { $this->showForm(_('Couldn’t get a request token.')); return; } /* Create an OMB_Profile from $user. */ $profile = $user->getProfile(); if (!$profile) { common_log_db_error($user, 'SELECT', __FILE__); $this->serverError(_('User without matching profile.')); return; } $target_url = $service->requestAuthorization(profile_to_omb_profile($user->uri, $profile), common_local_url('finishremotesubscribe')); common_ensure_session(); $_SESSION['oauth_authorization_request'] = serialize($service); /* Redirect to the remote service for authorization. */ common_redirect($target_url, 303); }
public static function updateProfile(Profile $profile, ActivityObject $object, array $hints = array()) { $orig = clone $profile; // Existing nickname is better than nothing. if (!array_key_exists('nickname', $hints)) { $hints['nickname'] = $profile->nickname; } $nickname = self::getActivityObjectNickname($object, $hints); if (!empty($nickname)) { $profile->nickname = $nickname; } if (!empty($object->title)) { $profile->fullname = $object->title; } else { if (array_key_exists('fullname', $hints)) { $profile->fullname = $hints['fullname']; } } if (!empty($object->link)) { $profile->profileurl = $object->link; } else { if (array_key_exists('profileurl', $hints)) { $profile->profileurl = $hints['profileurl']; } else { if (common_valid_http_url($object->id)) { $profile->profileurl = $object->id; } } } $bio = self::getActivityObjectBio($object, $hints); if (!empty($bio)) { $profile->bio = $bio; } $location = self::getActivityObjectLocation($object, $hints); if (!empty($location)) { $profile->location = $location; } $homepage = self::getActivityObjectHomepage($object, $hints); if (!empty($homepage)) { $profile->homepage = $homepage; } if (!empty($object->geopoint)) { $location = ActivityContext::locationFromPoint($object->geopoint); if (!empty($location)) { $profile->lat = $location->lat; $profile->lon = $location->lon; } } // @todo FIXME: tags/categories // @todo tags from categories if ($profile->id) { common_log(LOG_DEBUG, "Updating OStatus profile {$profile->id} from remote info {$object->id}: " . var_export($object, true) . var_export($hints, true)); $profile->update($orig); } }
function validateHomepage() { if (!is_null($this->homepage) && strlen($this->homepage) > 0 && !common_valid_http_url($this->homepage)) { throw new ApiValidationException(_('Homepage is not a valid URL.')); } }
private function trySave() { $name = $this->trimmed('name'); $description = $this->trimmed('description'); $source_url = $this->trimmed('source_url'); $organization = $this->trimmed('organization'); $homepage = $this->trimmed('homepage'); $callback_url = $this->trimmed('callback_url'); $type = $this->arg('app_type'); $access_type = $this->arg('default_access_type'); if (empty($name)) { // TRANS: Validation error shown when not providing a name in the "New application" form. $this->clientError(_('Name is required.')); } else { if ($this->nameExists($name)) { // TRANS: Validation error shown when providing a name for an application that already exists in the "New application" form. $this->clientError(_('Name already in use. Try another one.')); } elseif (mb_strlen($name) > 255) { // TRANS: Validation error shown when providing too long a name in the "New application" form. $this->clientError(_('Name is too long (maximum 255 characters).')); } elseif (empty($description)) { // TRANS: Validation error shown when not providing a description in the "New application" form. $this->clientError(_('Description is required.')); } elseif (Oauth_application::descriptionTooLong($description)) { $this->clientError(sprintf(_m('Description is too long (maximum %d character).', 'Description is too long (maximum %d characters).', Oauth_application::maxDesc()), Oauth_application::maxDesc())); } elseif (empty($source_url)) { // TRANS: Validation error shown when not providing a source URL in the "New application" form. $this->clientError(_('Source URL is required.')); } elseif (strlen($source_url) > 0 && !common_valid_http_url($source_url)) { // TRANS: Validation error shown when providing an invalid source URL in the "New application" form. $this->clientError(_('Source URL is not valid.')); } elseif (empty($organization)) { // TRANS: Validation error shown when not providing an organisation in the "New application" form. $this->clientError(_('Organization is required.')); } elseif (mb_strlen($organization) > 255) { // TRANS: Validation error shown when providing too long an arganisation name in the "Edit application" form. $this->clientError(_('Organization is too long (maximum 255 characters).')); } elseif (empty($homepage)) { // TRANS: Form validation error show when an organisation name has not been provided in the new application form. $this->clientError(_('Organization homepage is required.')); } elseif (strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Validation error shown when providing an invalid homepage URL in the "New application" form. $this->clientError(_('Homepage is not a valid URL.')); } elseif (mb_strlen($callback_url) > 255) { // TRANS: Validation error shown when providing too long a callback URL in the "New application" form. $this->clientError(_('Callback is too long.')); } elseif (strlen($callback_url) > 0 && !common_valid_http_url($callback_url)) { // TRANS: Validation error shown when providing an invalid callback URL in the "New application" form. $this->clientError(_('Callback URL is not valid.')); } } // Login is checked in parent::prepare() assert(!is_null($this->scoped)); $app = new Oauth_application(); $app->query('BEGIN'); $app->name = $name; $app->owner = $this->scoped->id; $app->description = $description; $app->source_url = $source_url; $app->organization = $organization; $app->homepage = $homepage; $app->callback_url = $callback_url; $app->type = $type; // Yeah, I dunno why I chose bit flags. I guess so I could // copy this value directly to Oauth_application_user // access_type which I think does need bit flags -- Z if ($access_type == 'r') { $app->setAccessFlags(true, false); } else { $app->setAccessFlags(true, true); } $app->created = common_sql_now(); // generate consumer key and secret $consumer = Consumer::generateNew(); $result = $consumer->insert(); if (!$result) { common_log_db_error($consumer, 'INSERT', __FILE__); $app->query('ROLLBACK'); // TRANS: Server error displayed when an application could not be registered in the database through the "New application" form. $this->serverError(_('Could not create application.')); } $app->consumer_key = $consumer->consumer_key; $this->app_id = $app->insert(); if (!$this->app_id) { common_log_db_error($app, 'INSERT', __FILE__); $app->query('ROLLBACK'); // TRANS: Server error displayed when an application could not be registered in the database through the "New application" form. $this->serverError(_('Could not create application.')); } try { $app->uploadLogo(); } catch (Exception $e) { $app->query('ROLLBACK'); // TRANS: Form validation error messages displayed when uploading an invalid application logo. $this->clientError(_('Invalid image.')); } $app->query('COMMIT'); common_redirect(common_local_url('oauthappssettings'), 303); }
function trySave() { $cur = common_current_user(); if (!$cur->isAdmin($this->group)) { // TRANS: Client error displayed trying to edit a group while not being a group admin. $this->clientError(_('You must be an admin to edit the group.'), 403); } if (Event::handle('StartGroupSaveForm', array($this))) { // $nickname will only be set if this changenick value is true. if (common_config('profile', 'changenick') == true) { try { $nickname = Nickname::normalize($this->trimmed('newnickname'), true); } catch (NicknameTakenException $e) { // Abort only if the nickname is occupied by _another_ group if ($e->profile->id != $this->group->profile_id) { $this->showForm($e->getMessage()); return; } $nickname = Nickname::normalize($this->trimmed('newnickname')); // without in-use check this time } catch (NicknameException $e) { $this->showForm($e->getMessage()); return; } } $fullname = $this->trimmed('fullname'); $homepage = $this->trimmed('homepage'); $description = $this->trimmed('description'); $location = $this->trimmed('location'); $aliasstring = $this->trimmed('aliases'); $private = $this->boolean('private'); if ($private) { $force_scope = 1; $join_policy = User_group::JOIN_POLICY_MODERATE; } else { $force_scope = 0; $join_policy = User_group::JOIN_POLICY_OPEN; } if (!is_null($homepage) && strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Group edit form validation error. $this->showForm(_('Homepage is not a valid URL.')); return; } else { if (!is_null($fullname) && mb_strlen($fullname) > 255) { // TRANS: Group edit form validation error. $this->showForm(_('Full name is too long (maximum 255 characters).')); return; } else { if (User_group::descriptionTooLong($description)) { $this->showForm(sprintf(_m('Description is too long (maximum %d character).', 'Description is too long (maximum %d characters).', User_group::maxDescription()), User_group::maxDescription())); return; } else { if (!is_null($location) && mb_strlen($location) > 255) { // TRANS: Group edit form validation error. $this->showForm(_('Location is too long (maximum 255 characters).')); return; } } } } if (!empty($aliasstring)) { $aliases = array_map(array('Nickname', 'normalize'), array_unique(preg_split('/[\\s,]+/', $aliasstring))); } else { $aliases = array(); } if (count($aliases) > common_config('group', 'maxaliases')) { // TRANS: Group edit form validation error. // TRANS: %d is the maximum number of allowed aliases. $this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.', 'Too many aliases! Maximum %d allowed.', common_config('group', 'maxaliases')), common_config('group', 'maxaliases'))); return; } $this->group->query('BEGIN'); $orig = clone $this->group; if (common_config('profile', 'changenick') == true && $this->group->nickname !== $nickname) { assert(Nickname::normalize($nickname) === $nickname); common_debug("Changing group nickname from '{$profile->nickname}' to '{$nickname}'."); $this->group->nickname = $nickname; $this->group->mainpage = common_local_url('showgroup', array('nickname' => $this->group->nickname)); } $this->group->fullname = $fullname; $this->group->homepage = $homepage; $this->group->description = $description; $this->group->location = $location; $this->group->join_policy = $join_policy; $this->group->force_scope = $force_scope; $result = $this->group->update($orig); if ($result === false) { common_log_db_error($this->group, 'UPDATE', __FILE__); // TRANS: Server error displayed when editing a group fails. $this->serverError(_('Could not update group.')); } $result = $this->group->setAliases($aliases); if (!$result) { // TRANS: Server error displayed when group aliases could not be added. $this->serverError(_('Could not create aliases.')); } $this->group->query('COMMIT'); Event::handle('EndGroupSaveForm', array($this)); } if ($this->group->nickname != $orig->nickname) { common_redirect(common_local_url('editgroup', array('nickname' => $this->group->nickname)), 303); } else { // TRANS: Group edit form success message. $this->showForm(_('Options saved.')); } }
/** * Validate License admin form values * * @param array &$values from the form * * @return nothing */ function validate(&$values) { // Validate license type (shouldn't have to do it, but just in case) $types = array('private', 'allrightsreserved', 'cc'); if (!in_array($values['license']['type'], $types)) { // TRANS: Client error displayed selecting an invalid license in the license admin panel. $this->clientError(_('Invalid license selection.')); } // Make sure the user has set an owner if the site has a private // license if ($values['license']['type'] == 'allrightsreserved' && empty($values['license']['owner'])) { $this->clientError(_('You must specify the owner of the content when using the All Rights Reserved license.')); } // Make sure the license title is not too long if (mb_strlen($values['license']['type']) > 255) { $this->clientError(_('Invalid license title. Maximum length is 255 characters.')); } // URLs should be set for cc license if ($values['license']['type'] == 'cc') { if (!common_valid_http_url($values['license']['url'])) { // TRANS: Client error displayed specifying an invalid license URL in the license admin panel. $this->clientError(_('Invalid license URL.')); } if (!common_valid_http_url($values['license']['image'])) { // TRANS: Client error displayed specifying an invalid license image URL in the license admin panel. $this->clientError(_('Invalid license image URL.')); } } // can be either blank or a valid URL for private & allrightsreserved if (!empty($values['license']['url'])) { if (!common_valid_http_url($values['license']['url'])) { // TRANS: Client error displayed specifying an invalid license URL in the license admin panel. $this->clientError(_('License URL must be blank or a valid URL.')); } } // can be either blank or a valid URL for private & allrightsreserved if (!empty($values['license']['image'])) { if (!common_valid_http_url($values['license']['image'])) { // TRANS: Client error displayed specifying an invalid license image URL in the license admin panel. $this->clientError(_('License image must be blank or valid URL.')); } } }
/** * Handle a post * * Validate input and save changes. Reload the form with a success * or error message. * * @return void */ protected function doPost() { if (Event::handle('StartProfileSaveForm', array($this))) { // $nickname will only be set if this changenick value is true. if (common_config('profile', 'changenick') == true) { try { $nickname = Nickname::normalize($this->trimmed('nickname'), true); } catch (NicknameTakenException $e) { // Abort only if the nickname is occupied by _another_ local user profile if (!$this->scoped->sameAs($e->profile)) { throw $e; } // Since the variable wasn't set before the exception was thrown, let's run // the normalize sequence again, but without in-use check this time. $nickname = Nickname::normalize($this->trimmed('nickname')); } } $fullname = $this->trimmed('fullname'); $homepage = $this->trimmed('homepage'); $bio = $this->trimmed('bio'); $location = $this->trimmed('location'); $autosubscribe = $this->booleanintstring('autosubscribe'); $subscribe_policy = $this->trimmed('subscribe_policy'); $private_stream = $this->booleanintstring('private_stream'); $language = $this->trimmed('language'); $timezone = $this->trimmed('timezone'); $tagstring = $this->trimmed('tags'); // Some validation if (!is_null($homepage) && strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Validation error in form for profile settings. throw new ClientException(_('Homepage is not a valid URL.')); } else { if (!is_null($fullname) && mb_strlen($fullname) > 191) { // TRANS: Validation error in form for profile settings. throw new ClientException(_('Full name is too long (maximum 191 characters).')); } else { if (Profile::bioTooLong($bio)) { // TRANS: Validation error in form for profile settings. // TRANS: Plural form is used based on the maximum number of allowed // TRANS: characters for the biography (%d). throw new ClientException(sprintf(_m('Bio is too long (maximum %d character).', 'Bio is too long (maximum %d characters).', Profile::maxBio()), Profile::maxBio())); } else { if (!is_null($location) && mb_strlen($location) > 191) { // TRANS: Validation error in form for profile settings. throw new ClientException(_('Location is too long (maximum 191 characters).')); } else { if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) { // TRANS: Validation error in form for profile settings. throw new ClientException(_('Timezone not selected.')); } else { if (!is_null($language) && strlen($language) > 50) { // TRANS: Validation error in form for profile settings. throw new ClientException(_('Language is too long (maximum 50 characters).')); } } } } } } $tags = array(); $tag_priv = array(); if (is_string($tagstring) && strlen($tagstring) > 0) { $tags = preg_split('/[\\s,]+/', $tagstring); foreach ($tags as &$tag) { $private = @$tag[0] === '.'; $tag = common_canonical_tag($tag); if (!common_valid_profile_tag($tag)) { // TRANS: Validation error in form for profile settings. // TRANS: %s is an invalid tag. throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag)); } $tag_priv[$tag] = $private; } } $user = $this->scoped->getUser(); $user->query('BEGIN'); // $user->nickname is updated through Profile->update(); // XXX: XOR if ($user->autosubscribe ^ $autosubscribe || $user->private_stream ^ $private_stream || $user->timezone != $timezone || $user->language != $language || $user->subscribe_policy != $subscribe_policy) { $original = clone $user; $user->autosubscribe = $autosubscribe; $user->language = $language; $user->private_stream = $private_stream; $user->subscribe_policy = $subscribe_policy; $user->timezone = $timezone; $result = $user->update($original); if ($result === false) { common_log_db_error($user, 'UPDATE', __FILE__); $user->query('ROLLBACK'); // TRANS: Server error thrown when user profile settings could not be updated to // TRANS: automatically subscribe to any subscriber. throw new ServerException(_('Could not update user for autosubscribe or subscribe_policy.')); } // Re-initialize language environment if it changed common_init_language(); } $original = clone $this->scoped; if (common_config('profile', 'changenick') == true && $this->scoped->getNickname() !== $nickname) { assert(Nickname::normalize($nickname) === $nickname); common_debug("Changing user nickname from '{$this->scoped->getNickname()}' to '{$nickname}'."); $this->scoped->nickname = $nickname; $this->scoped->profileurl = common_profile_url($this->scoped->getNickname()); } $this->scoped->fullname = $fullname; $this->scoped->homepage = $homepage; $this->scoped->bio = $bio; $this->scoped->location = $location; $loc = Location::fromName($location); if (empty($loc)) { $this->scoped->lat = null; $this->scoped->lon = null; $this->scoped->location_id = null; $this->scoped->location_ns = null; } else { $this->scoped->lat = $loc->lat; $this->scoped->lon = $loc->lon; $this->scoped->location_id = $loc->location_id; $this->scoped->location_ns = $loc->location_ns; } if (common_config('location', 'share') == 'user') { $exists = false; $prefs = User_location_prefs::getKV('user_id', $this->scoped->getID()); if (empty($prefs)) { $prefs = new User_location_prefs(); $prefs->user_id = $this->scoped->getID(); $prefs->created = common_sql_now(); } else { $exists = true; $orig = clone $prefs; } $prefs->share_location = $this->booleanintstring('sharelocation'); if ($exists) { $result = $prefs->update($orig); } else { $result = $prefs->insert(); } if ($result === false) { common_log_db_error($prefs, $exists ? 'UPDATE' : 'INSERT', __FILE__); $user->query('ROLLBACK'); // TRANS: Server error thrown when user profile location preference settings could not be updated. throw new ServerException(_('Could not save location prefs.')); } } common_debug('Old profile: ' . common_log_objstring($original), __FILE__); common_debug('New profile: ' . common_log_objstring($this->scoped), __FILE__); $result = $this->scoped->update($original); if ($result === false) { common_log_db_error($this->scoped, 'UPDATE', __FILE__); $user->query('ROLLBACK'); // TRANS: Server error thrown when user profile settings could not be saved. throw new ServerException(_('Could not save profile.')); } // Set the user tags $result = Profile_tag::setSelfTags($this->scoped, $tags, $tag_priv); $user->query('COMMIT'); Event::handle('EndProfileSaveForm', array($this)); // TRANS: Confirmation shown when user profile settings are saved. return _('Settings saved.'); } }
/** * Download and update given avatar image * * @param string $url * @param mixed $dest either a Profile or User_group object * @throws Exception in various failure cases */ private function saveAvatar($url, $dest) { // Yammer API data mostly gives us the small variant. // Try hitting the source image if we can! // @fixme no guarantee of this URL scheme I think. $url = preg_replace('/_small(\\..*?)$/', '$1', $url); if (!common_valid_http_url($url)) { throw new ServerException(sprintf(_m("Invalid avatar URL %s."), $url)); } // @fixme this should be better encapsulated // ripped from oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); try { if (!copy($url, $temp_filename)) { throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url)); } $id = $dest->id; // @fixme should we be using different ids? $imagefile = new ImageFile($id, $temp_filename); $filename = Avatar::filename($id, image_type_to_extension($imagefile->type), null, common_timestamp()); rename($temp_filename, Avatar::path($filename)); } catch (Exception $e) { unlink($temp_filename); throw $e; } // @fixme hardcoded chmod is lame, but seems to be necessary to // keep from accidentally saving images from command-line (queues) // that can't be read from web server, which causes hard-to-notice // problems later on: // // http://status.net/open-source/issues/2663 chmod(Avatar::path($filename), 0644); $dest->setOriginal($filename); }
/** * Get the identifier URI for the remote entity described * by this ActivityObject. This URI is *not* guaranteed to be * a resolvable HTTP/HTTPS URL. * * @param ActivityObject $object * @return string * @throws ServerException if feed info invalid */ protected static function getActivityObjectProfileURI($object) { if ($object->id) { if (ActivityUtils::validateUri($object->id)) { return $object->id; } } // If the id is missing or invalid (we've seen feeds mistakenly listing // things like local usernames in that field) then we'll use the profile // page link, if valid. if ($object->link && common_valid_http_url($object->link)) { return $object->link; } // TRANS: Server exception. throw new ServerException(_m('No author ID URI found.')); }
/** * Actually save the avatar we found locally. * * @param User $user * @param string $url to avatar URL * @todo merge wrapper funcs for this into common place for 1.0 core */ private function saveAvatar($user, $url) { if (!common_valid_http_url($url)) { // TRANS: Server exception thrown when an avatar URL is invalid. // TRANS: %s is the invalid avatar URL. throw new ServerException(sprintf(_m('Invalid avatar URL %s.'), $url)); } // @todo FIXME: This should be better encapsulated // ripped from OStatus via oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); try { if (!copy($url, $temp_filename)) { // TRANS: Exception thrown when fetching an avatar from a URL fails. // TRANS: %s is a URL. throw new ServerException(sprintf(_m('Unable to fetch avatar from %s.'), $url)); } $profile = $user->getProfile(); $id = $profile->id; $imagefile = new ImageFile(null, $temp_filename); $filename = Avatar::filename($id, image_type_to_extension($imagefile->type), null, common_timestamp()); rename($temp_filename, Avatar::path($filename)); } catch (Exception $e) { unlink($temp_filename); throw $e; } $profile->setOriginal($filename); }
static function saveActivity(Activity $act, Profile $actor, array $options = array()) { // First check if we're going to let this Activity through from the specific actor if (!$actor->hasRight(Right::NEWNOTICE)) { common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $actor->getNickname()); // TRANS: Client exception thrown when a user tries to post while being banned. throw new ClientException(_m('You are banned from posting notices on this site.'), 403); } if (common_config('throttle', 'enabled') && !self::checkEditThrottle($actor->id)) { common_log(LOG_WARNING, 'Excessive posting by profile #' . $actor->id . '; throttled.'); // TRANS: Client exception thrown when a user tries to post too many notices in a given time frame. throw new ClientException(_m('Too many notices too fast; take a breather ' . 'and post again in a few minutes.')); } // Get ActivityObject properties $actobj = null; if (!empty($act->id)) { // implied object $options['uri'] = $act->id; $options['url'] = $act->link; } else { $actobj = count($act->objects) == 1 ? $act->objects[0] : null; if (!is_null($actobj) && !empty($actobj->id)) { $options['uri'] = $actobj->id; if ($actobj->link) { $options['url'] = $actobj->link; } elseif (preg_match('!^https?://!', $actobj->id)) { $options['url'] = $actobj->id; } } } $defaults = array('groups' => array(), 'is_local' => $actor->isLocal() ? self::LOCAL_PUBLIC : self::REMOTE, 'mentions' => array(), 'reply_to' => null, 'repeat_of' => null, 'scope' => null, 'source' => 'unknown', 'tags' => array(), 'uri' => null, 'url' => null, 'urls' => array(), 'distribute' => true); // options will have default values when nothing has been supplied $options = array_merge($defaults, $options); foreach (array_keys($defaults) as $key) { // Only convert the keynames we specify ourselves from 'defaults' array into variables ${$key} = $options[$key]; } extract($options, EXTR_SKIP); // dupe check $stored = new Notice(); if (!empty($uri) && !ActivityUtils::compareVerbs($act->verb, array(ActivityVerb::DELETE))) { $stored->uri = $uri; if ($stored->find()) { common_debug('cannot create duplicate Notice URI: ' . $stored->uri); // I _assume_ saving a Notice with a colliding URI means we're really trying to // save the same notice again... throw new AlreadyFulfilledException('Notice URI already exists'); } } $autosource = common_config('public', 'autosource'); // Sandboxed are non-false, but not 1, either if (!$actor->hasRight(Right::PUBLICNOTICE) || $source && $autosource && in_array($source, $autosource)) { // FIXME: ...what about remote nonpublic? Hmmm. That is, if we sandbox remote profiles... $stored->is_local = Notice::LOCAL_NONPUBLIC; } else { $stored->is_local = intval($is_local); } if (!$stored->isLocal()) { // Only do these checks for non-local notices. Local notices will generate these values later. if (!common_valid_http_url($url)) { common_debug('Bad notice URL: [' . $url . '], URI: [' . $uri . ']. Cannot link back to original! This is normal for shared notices etc.'); } if (empty($uri)) { throw new ServerException('No URI for remote notice. Cannot accept that.'); } } $stored->profile_id = $actor->id; $stored->source = $source; $stored->uri = $uri; $stored->url = $url; $stored->verb = $act->verb; // Notice content. We trust local users to provide HTML we like, but of course not remote users. // FIXME: What about local users importing feeds? Mirror functions must filter out bad HTML first... $content = $act->content ?: $act->summary; if (is_null($content) && !is_null($actobj)) { $content = $actobj->content ?: $actobj->summary; } $stored->rendered = $actor->isLocal() ? $content : common_purify($content); // yeah, just don't use getRendered() here since it's not inserted yet ;) $stored->content = common_strip_html($stored->rendered); // Maybe a missing act-time should be fatal if the actor is not local? if (!empty($act->time)) { $stored->created = common_sql_date($act->time); } else { $stored->created = common_sql_now(); } $reply = null; if ($act->context instanceof ActivityContext && !empty($act->context->replyToID)) { $reply = self::getKV('uri', $act->context->replyToID); } if (!$reply instanceof Notice && $act->target instanceof ActivityObject) { $reply = self::getKV('uri', $act->target->id); } if ($reply instanceof Notice) { if (!$reply->inScope($actor)) { // TRANS: Client error displayed when trying to reply to a notice a the target has no access to. // TRANS: %1$s is a user nickname, %2$d is a notice ID (number). throw new ClientException(sprintf(_m('%1$s has no right to reply to notice %2$d.'), $actor->getNickname(), $reply->id), 403); } $stored->reply_to = $reply->id; $stored->conversation = $reply->conversation; // If the original is private to a group, and notice has no group specified, // make it to the same group(s) if (empty($groups) && $reply->scope & Notice::GROUP_SCOPE) { $replyGroups = $reply->getGroups(); foreach ($replyGroups as $group) { if ($actor->isMember($group)) { $groups[] = $group->id; } } } if (is_null($scope)) { $scope = $reply->scope; } } else { // If we don't know the reply, we might know the conversation! // This will happen if a known remote user replies to an // unknown remote user - within a known conversation. if (empty($stored->conversation) and !empty($act->context->conversation)) { $conv = Conversation::getKV('uri', $act->context->conversation); if ($conv instanceof Conversation) { common_debug('Conversation stitched together from (probably) a reply activity to unknown remote user. Activity creation time (' . $stored->created . ') should maybe be compared to conversation creation time (' . $conv->created . ').'); } else { // Conversation entry with specified URI was not found, so we must create it. common_debug('Conversation URI not found, so we will create it with the URI given in the context of the activity: ' . $act->context->conversation); // The insert in Conversation::create throws exception on failure $conv = Conversation::create($act->context->conversation, $stored->created); } $stored->conversation = $conv->getID(); unset($conv); } } // If it's not part of a conversation, it's the beginning of a new conversation. if (empty($stored->conversation)) { $conv = Conversation::create(); $stored->conversation = $conv->getID(); unset($conv); } $notloc = null; if ($act->context instanceof ActivityContext) { if ($act->context->location instanceof Location) { $notloc = Notice_location::fromLocation($act->context->location); } } else { $act->context = new ActivityContext(); } $stored->scope = self::figureOutScope($actor, $groups, $scope); foreach ($act->categories as $cat) { if ($cat->term) { $term = common_canonical_tag($cat->term); if (!empty($term)) { $tags[] = $term; } } } foreach ($act->enclosures as $href) { // @todo FIXME: Save these locally or....? $urls[] = $href; } if (ActivityUtils::compareVerbs($stored->verb, array(ActivityVerb::POST))) { if (empty($act->objects[0]->type)) { // Default type for the post verb is 'note', but we know it's // a 'comment' if it is in reply to something. $stored->object_type = empty($stored->reply_to) ? ActivityObject::NOTE : ActivityObject::COMMENT; } else { //TODO: Is it safe to always return a relative URI? The // JSON version of ActivityStreams always use it, so we // should definitely be able to handle it... $stored->object_type = ActivityUtils::resolveUri($act->objects[0]->type, true); } } if (Event::handle('StartNoticeSave', array(&$stored))) { // XXX: some of these functions write to the DB try { $result = $stored->insert(); // throws exception on error if ($notloc instanceof Notice_location) { $notloc->notice_id = $stored->getID(); $notloc->insert(); } $orig = clone $stored; // for updating later in this try clause $object = null; Event::handle('StoreActivityObject', array($act, $stored, $options, &$object)); if (empty($object)) { throw new ServerException('Unsuccessful call to StoreActivityObject ' . $stored->getUri() . ': ' . $act->asString()); } // If something changed in the Notice during StoreActivityObject $stored->update($orig); } catch (Exception $e) { if (empty($stored->id)) { common_debug('Failed to save stored object entry in database (' . $e->getMessage() . ')'); } else { common_debug('Failed to store activity object in database (' . $e->getMessage() . '), deleting notice id ' . $stored->id); $stored->delete(); } throw $e; } } if (!$stored instanceof Notice) { throw new ServerException('StartNoticeSave did not give back a Notice'); } // Only save 'attention' and metadata stuff (URLs, tags...) stuff if // the activityverb is a POST (since stuff like repeat, favorite etc. // reasonably handle notifications themselves. if (ActivityUtils::compareVerbs($stored->verb, array(ActivityVerb::POST))) { if (!empty($tags)) { $stored->saveKnownTags($tags); } else { $stored->saveTags(); } // Note: groups may save tags, so must be run after tags are saved // to avoid errors on duplicates. $stored->saveAttentions($act->context->attention); if (!empty($urls)) { $stored->saveKnownUrls($urls); } else { $stored->saveUrls(); } } if ($distribute) { // Prepare inbox delivery, may be queued to background. $stored->distribute(); } return $stored; }
function trySave() { $name = $this->trimmed('name'); $description = $this->trimmed('description'); $source_url = $this->trimmed('source_url'); $organization = $this->trimmed('organization'); $homepage = $this->trimmed('homepage'); $callback_url = $this->trimmed('callback_url'); $type = $this->arg('app_type'); $access_type = $this->arg('default_access_type'); if (empty($name)) { // TRANS: Validation error shown when not providing a name in the "Edit application" form. $this->showForm(_('Name is required.')); return; } elseif (mb_strlen($name) > 255) { // TRANS: Validation error shown when providing too long a name in the "Edit application" form. $this->showForm(_('Name is too long (maximum 255 characters).')); return; } else { if ($this->nameExists($name)) { // TRANS: Validation error shown when providing a name for an application that already exists in the "Edit application" form. $this->showForm(_('Name already in use. Try another one.')); return; } elseif (empty($description)) { // TRANS: Validation error shown when not providing a description in the "Edit application" form. $this->showForm(_('Description is required.')); return; } elseif (Oauth_application::descriptionTooLong($description)) { $this->showForm(sprintf(_m('Description is too long (maximum %d character).', 'Description is too long (maximum %d characters).', Oauth_application::maxDesc()), Oauth_application::maxDesc())); return; } elseif (mb_strlen($source_url) > 255) { // TRANS: Validation error shown when providing too long a source URL in the "Edit application" form. $this->showForm(_('Source URL is too long.')); return; } elseif (mb_strlen($source_url) > 0 && !common_valid_http_url($source_url)) { // TRANS: Validation error shown when providing an invalid source URL in the "Edit application" form. $this->showForm(_('Source URL is not valid.')); return; } elseif (empty($organization)) { // TRANS: Validation error shown when not providing an organisation in the "Edit application" form. $this->showForm(_('Organization is required.')); return; } elseif (mb_strlen($organization) > 255) { // TRANS: Validation error shown when providing too long an arganisation name in the "Edit application" form. $this->showForm(_('Organization is too long (maximum 255 characters).')); return; } elseif (empty($homepage)) { // TRANS: Form validation error show when an organisation name has not been provided in the edit application form. $this->showForm(_('Organization homepage is required.')); return; } elseif (mb_strlen($homepage) > 0 && !common_valid_http_url($homepage)) { // TRANS: Validation error shown when providing an invalid homepage URL in the "Edit application" form. $this->showForm(_('Homepage is not a valid URL.')); return; } elseif (mb_strlen($callback_url) > 255) { // TRANS: Validation error shown when providing too long a callback URL in the "Edit application" form. $this->showForm(_('Callback is too long.')); return; } elseif (mb_strlen($callback_url) > 0 && !common_valid_http_url($callback_url)) { // TRANS: Validation error shown when providing an invalid callback URL in the "Edit application" form. $this->showForm(_('Callback URL is not valid.')); return; } } $cur = common_current_user(); // Checked in prepare() above assert(!is_null($cur)); assert(!is_null($this->app)); $orig = clone $this->app; $this->app->name = $name; $this->app->description = $description; $this->app->source_url = $source_url; $this->app->organization = $organization; $this->app->homepage = $homepage; $this->app->callback_url = $callback_url; $this->app->type = $type; common_debug("access_type = {$access_type}"); if ($access_type == 'r') { $this->app->access_type = 1; } else { $this->app->access_type = 3; } $result = $this->app->update($orig); // Note: 0 means no rows changed, which can happen if the only // thing we changed was the icon, since it's not altered until // the next step. if ($result === false) { common_log_db_error($this->app, 'UPDATE', __FILE__); // TRANS: Server error occuring when an application could not be updated from the "Edit application" form. $this->serverError(_('Could not update application.')); } $this->app->uploadLogo(); common_redirect(common_local_url('oauthappssettings'), 303); }
function validateOmb() { $listener = $_GET['omb_listener']; $listenee = $_GET['omb_listenee']; $nickname = $_GET['omb_listenee_nickname']; $profile = $_GET['omb_listenee_profile']; $user = User::staticGet('uri', $listener); if (!$user) { throw new Exception(sprintf(_('Listener URI ‘%s’ not found here.'), $listener)); } if (strlen($listenee) > 255) { throw new Exception(sprintf(_('Listenee URI ‘%s’ is too long.'), $listenee)); } $other = User::staticGet('uri', $listenee); if ($other) { throw new Exception(sprintf(_('Listenee URI ‘%s’ is a local user.'), $listenee)); } $remote = Remote_profile::staticGet('uri', $listenee); if ($remote) { $sub = new Subscription(); $sub->subscriber = $user->id; $sub->subscribed = $remote->id; if ($sub->find(true)) { throw new Exception('You are already subscribed to this user.'); } } if ($profile == common_profile_url($nickname)) { throw new Exception(sprintf(_('Profile URL ‘%s’ is for a local user.'), $profile)); } $license = $_GET['omb_listenee_license']; $site_license = common_config('license', 'url'); if (!common_compatible_license($license, $site_license)) { throw new Exception(sprintf(_('Listenee stream license ‘%1$s’ is not ' . 'compatible with site license ‘%2$s’.'), $license, $site_license)); } $avatar = $_GET['omb_listenee_avatar']; if ($avatar) { if (!common_valid_http_url($avatar) || strlen($avatar) > 255) { throw new Exception(sprintf(_('Avatar URL ‘%s’ is not valid.'), $avatar)); } $size = @getimagesize($avatar); if (!$size) { throw new Exception(sprintf(_('Can’t read avatar URL ‘%s’.'), $avatar)); } if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG))) { throw new Exception(sprintf(_('Wrong image type for avatar URL ' . '‘%s’.'), $avatar)); } } }
function saveWebsites($user) { $sites = $this->findWebsites(); $this->removeAll($user, 'website'); $i = 0; foreach ($sites as $site) { if (!empty($site['value']) && !common_valid_http_url($site['value'])) { // TRANS: Exception thrown when entering an invalid URL. // TRANS: %s is the invalid URL. throw new Exception(sprintf(_m('Invalid URL: %s.'), $site['value'])); } if (!empty($site['value'])) { ++$i; $this->saveField($user, 'website', $site['value'], $site['rel'], $i); } } }
/** * Save a new notice bookmark * * @param Profile $profile To save the bookmark for * @param string $title Title of the bookmark * @param string $url URL of the bookmark * @param mixed $rawtags array of tags or string * @param string $description Description of the bookmark * @param array $options Options for the Notice::saveNew() * * @return Notice saved notice */ static function saveNew($profile, $title, $url, $rawtags, $description, $options = null) { if (!common_valid_http_url($url)) { throw new ClientException(_m('Only web bookmarks can be posted (HTTP or HTTPS).')); } $nb = self::getByURL($profile, $url); if (!empty($nb)) { // TRANS: Client exception thrown when trying to save a new bookmark that already exists. throw new ClientException(_m('Bookmark already exists.')); } if (empty($options)) { $options = array(); } if (array_key_exists('uri', $options)) { $other = Bookmark::getKV('uri', $options['uri']); if (!empty($other)) { // TRANS: Client exception thrown when trying to save a new bookmark that already exists. throw new ClientException(_m('Bookmark already exists.')); } } if (is_string($rawtags)) { if (empty($rawtags)) { $rawtags = array(); } else { $rawtags = preg_split('/[\\s,]+/', $rawtags); } } $nb = new Bookmark(); $nb->id = UUID::gen(); $nb->profile_id = $profile->id; $nb->url = $url; $nb->title = $title; $nb->description = $description; if (array_key_exists('created', $options)) { $nb->created = $options['created']; } else { $nb->created = common_sql_now(); } if (array_key_exists('uri', $options)) { $nb->uri = $options['uri']; } else { // FIXME: hacks to work around router bugs in // queue daemons $r = Router::get(); $path = $r->build('showbookmark', array('id' => $nb->id)); if (empty($path)) { $nb->uri = common_path('bookmark/' . $nb->id, false, false); } else { $nb->uri = common_local_url('showbookmark', array('id' => $nb->id), null, null, false); } } $nb->insert(); $tags = array(); $replies = array(); // filter "for:nickname" tags foreach ($rawtags as $tag) { if (strtolower(mb_substr($tag, 0, 4)) == 'for:') { // skip if done by caller if (!array_key_exists('replies', $options)) { $nickname = mb_substr($tag, 4); $other = common_relative_profile($profile, $nickname); if (!empty($other)) { $replies[] = $other->getUri(); } } } else { $tags[] = common_canonical_tag($tag); } } $hashtags = array(); $taglinks = array(); foreach ($tags as $tag) { $hashtags[] = '#' . $tag; $attrs = array('href' => Notice_tag::url($tag), 'rel' => $tag, 'class' => 'tag'); $taglinks[] = XMLStringer::estring('a', $attrs, $tag); } // Use user's preferences for short URLs, if possible try { $user = User::getKV('id', $profile->id); $shortUrl = File_redirection::makeShort($url, empty($user) ? null : $user); } catch (Exception $e) { // Don't let this stop us. $shortUrl = $url; } // TRANS: Bookmark content. // TRANS: %1$s is a title, %2$s is a short URL, %3$s is the bookmark description, // TRANS: %4$s is space separated list of hash tags. $content = sprintf(_m('"%1$s" %2$s %3$s %4$s'), $title, $shortUrl, $description, implode(' ', $hashtags)); // TRANS: Rendered bookmark content. // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description, // TRANS: %4$s is space separated list of hash tags. $rendered = sprintf(_m('<span class="xfolkentry">' . '<a class="taggedlink" href="%1$s">%2$s</a> ' . '<span class="description">%3$s</span> ' . '<span class="meta">%4$s</span>' . '</span>'), htmlspecialchars($url), htmlspecialchars($title), htmlspecialchars($description), implode(' ', $taglinks)); $options = array_merge(array('urls' => array($url), 'rendered' => $rendered, 'tags' => $tags, 'replies' => $replies, 'object_type' => ActivityObject::BOOKMARK), $options); if (!array_key_exists('uri', $options)) { $options['uri'] = $nb->uri; } try { $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options); } catch (Exception $e) { $nb->delete(); throw $e; } if (empty($saved)) { $nb->delete(); } return $saved; }
function validateOmb() { $listener = $_GET['omb_listener']; $listenee = $_GET['omb_listenee']; $nickname = $_GET['omb_listenee_nickname']; $profile = $_GET['omb_listenee_profile']; $user = User::staticGet('uri', $listener); if (!$user) { // TRANS: Exception thrown when no valid user is found for an authorisation request. // TRANS: %s is a listener URI. throw new Exception(sprintf(_('Listener URI "%s" not found here.'), $listener)); } if (strlen($listenee) > 255) { // TRANS: Exception thrown when listenee URI is too long for an authorisation request. // TRANS: %s is a listenee URI. throw new Exception(sprintf(_('Listenee URI "%s" is too long.'), $listenee)); } $other = User::staticGet('uri', $listenee); if ($other) { // TRANS: Exception thrown when listenee URI is a local user for an authorisation request. // TRANS: %s is a listenee URI. throw new Exception(sprintf(_('Listenee URI "%s" is a local user.'), $listenee)); } $remote = Remote_profile::staticGet('uri', $listenee); if ($remote) { $sub = new Subscription(); $sub->subscriber = $user->id; $sub->subscribed = $remote->id; if ($sub->find(true)) { // TRANS: Exception thrown when already subscribed. throw new Exception('You are already subscribed to this user.'); } } if ($profile == common_profile_url($nickname)) { // TRANS: Exception thrown when profile URL is a local user for an authorisation request. // TRANS: %s is a profile URL. throw new Exception(sprintf(_('Profile URL "%s" is for a local user.'), $profile)); } $license = $_GET['omb_listenee_license']; $site_license = common_config('license', 'url'); if (!common_compatible_license($license, $site_license)) { // TRANS: Exception thrown when licenses are not compatible for an authorisation request. // TRANS: %1$s is the license for the listenee, %2$s is the license for "this" StatusNet site. throw new Exception(sprintf(_('Listenee stream license "%1$s" is not ' . 'compatible with site license "%2$s".'), $license, $site_license)); } $avatar = $_GET['omb_listenee_avatar']; if ($avatar) { if (!common_valid_http_url($avatar) || strlen($avatar) > 255) { // TRANS: Exception thrown when avatar URL is invalid for an authorisation request. // TRANS: %s is an avatar URL. throw new Exception(sprintf(_('Avatar URL "%s" is not valid.'), $avatar)); } $size = @getimagesize($avatar); if (!$size) { // TRANS: Exception thrown when avatar URL could not be read for an authorisation request. // TRANS: %s is an avatar URL. throw new Exception(sprintf(_('Cannot read avatar URL "%s".'), $avatar)); } if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG))) { // TRANS: Exception thrown when avatar URL return an invalid image type for an authorisation request. // TRANS: %s is an avatar URL. throw new Exception(sprintf(_('Wrong image type for avatar URL ' . '"%s".'), $avatar)); } } }