]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/nickname.php
Faster NodeInfo stats
[quix0rs-gnu-social.git] / lib / nickname.php
index 2792d32fd50494900a01e4cbf09a55617d1fab5c..e21517497a18cd0587530bc14519fb9ebf310ff5 100644 (file)
@@ -27,8 +27,7 @@ class Nickname
      * Nickname::normalize() to get the canonical form, or Nickname::isValid()
      * if you just need to check if it's properly formatted.
      *
-     * This, DISPLAY_FMT, and CANONICAL_FMT replace the old NICKNAME_FMT,
-     * but be aware that these should not be enclosed in []s.
+     * This, DISPLAY_FMT, and CANONICAL_FMT should not be enclosed in []s.
      *
      * @fixme would prefer to define in reference to the other constants
      */
@@ -36,6 +35,7 @@ class Nickname
 
     /**
      * Regex fragment for acceptable user-formatted variant of a nickname.
+     *
      * This includes some chars such as underscore which will be removed
      * from the normalized canonical form, but still must fit within
      * field length limits.
@@ -44,11 +44,21 @@ class Nickname
      * Nickname::normalize() to get the canonical form, or Nickname::isValid()
      * if you just need to check if it's properly formatted.
      *
-     * This and CANONICAL_FMT replace the old NICKNAME_FMT, but be aware
-     * that these should not be enclosed in []s.
+     * This, INPUT_FMT and CANONICAL_FMT should not be enclosed in []s.
      */
     const DISPLAY_FMT = '[0-9a-zA-Z_]{1,64}';
 
+    /**
+     * Simplified regex fragment for acceptable full WebFinger ID of a user
+     *
+     * We could probably use an email regex here, but mainly we are interested
+     * in matching it in our URLs, like https://social.example/user@example.com
+     */
+    const WEBFINGER_FMT = '(?:\w+[\w\-\_\.]*)?\w+\@'.URL_REGEX_DOMAIN_NAME;
+
+    // old one without support for -_. in nickname part:
+    // const WEBFINGER_FMT = '[0-9a-zA-Z_]{1,64}\@[0-9a-zA-Z_-.]{3,255}';
+
     /**
      * Regex fragment for checking a canonical nickname.
      *
@@ -60,8 +70,7 @@ class Nickname
      * there are multiple possible denormalized forms for each valid
      * canonical-form name.
      *
-     * This and DISPLAY_FMT replace the old NICKNAME_FMT, but be aware
-     * that these should not be enclosed in []s.
+     * This, INPUT_FMT and DISPLAY_FMT should not be enclosed in []s.
      */
     const CANONICAL_FMT = '[0-9a-z]{1,64}';
 
@@ -70,6 +79,16 @@ class Nickname
      */
     const MAX_LEN = 64;
 
+    /**
+     * Regex with non-capturing group that matches whitespace and some
+     * characters which are allowed right before an @ or ! when mentioning
+     * other users. Like: 'This goes out to:@mmn (@chimo too) (!awwyiss).'
+     *
+     * FIXME: Make this so you can have multiple whitespace but not multiple
+     * parenthesis or something. '(((@n_n@)))' might as well be a smiley.
+     */
+    const BEFORE_MENTIONS = '(?:^|[\s\.\,\:\;\[\(]+)';
+
     /**
      * Nice simple check of whether the given string is a valid input nickname,
      * which can be normalized into an internally canonical form.
@@ -110,15 +129,17 @@ class Nickname
      */
     public static function normalize($str, $checkuse=false)
     {
+        if (mb_strlen($str) > self::MAX_LEN) {
+            // Display forms must also fit!
+            throw new NicknameTooLongException();
+        }
+
         // We should also have UTF-8 normalization (å to a etc.)
         $str = trim($str);
         $str = str_replace('_', '', $str);
         $str = mb_strtolower($str);
 
-        if (mb_strlen($str) > self::MAX_LEN) {
-            // Display forms must also fit!
-            throw new NicknameTooLongException();
-        } elseif (mb_strlen($str) < 1) {
+        if (mb_strlen($str) < 1) {
             throw new NicknameEmptyException();
         } elseif (!self::isCanonical($str)) {
             throw new NicknameInvalidException();
@@ -126,9 +147,10 @@ class Nickname
             throw new NicknameBlacklistedException();
         } elseif (self::isSystemPath($str)) {
             throw new NicknamePathCollisionException();
-        } elseif ($checkuse && $user = self::isTaken($str)) {
-            if ($user instanceof User) {
-                throw new NicknameTakenException($user);
+        } elseif ($checkuse) {
+            $profile = self::isTaken($str);
+            if ($profile instanceof Profile) {
+                throw new NicknameTakenException($profile);
             }
         }
 
@@ -155,6 +177,8 @@ class Nickname
      public static function isBlacklisted($str)
      {
          $blacklist = common_config('nickname', 'blacklist');
+         if(!$blacklist)
+               return false;
          return in_array($str, $blacklist);
      }
 
@@ -173,30 +197,50 @@ class Nickname
         // All directory and file names in site root should be blacklisted
         $d = dir(INSTALLDIR);
         while (false !== ($entry = $d->read())) {
-            $paths[] = $entry;
+            $paths[$entry] = true;
         }
         $d->close();
 
         // All top level names in the router should be blacklisted
         $router = Router::get();
-        foreach (array_keys($router->m->getPaths()) as $path) {
-            if (preg_match('/^\/(.*?)[\/\?]/',$path,$matches)) {
-                $paths[] = $matches[1];
+        foreach ($router->m->getPaths() as $path) {
+            if (preg_match('/^([^\/\?]+)[\/\?]/',$path,$matches) && isset($matches[1])) {
+                $paths[$matches[1]] = true;
             }
         }
-        return in_array($str, $paths);
+
+        // FIXME: this assumes the 'path' is in the first-level directory, though common it's not certain
+        foreach (['avatar', 'attachments'] as $cat) {
+            $paths[basename(common_config($cat, 'path'))] = true;
+        }
+
+        return in_array($str, array_keys($paths));
     }
 
     /**
      * Is the nickname already in use locally? Checks the User table.
      *
      * @param   string $str
-     * @return  User|null   Returns null if no such user, otherwise a User object
+     * @return  Profile|null   Returns Profile if nickname found, otherwise null
      */
     public static function isTaken($str)
     {
-        $user = User::getKV('nickname', $str);
-        return $user;   // null if no such User entry
+        $found = User::getKV('nickname', $str);
+        if ($found instanceof User) {
+            return $found->getProfile();
+        }
+
+        $found = Local_group::getKV('nickname', $str);
+        if ($found instanceof Local_group) {
+            return $found->getProfile();
+        }
+
+        $found = Group_alias::getKV('alias', $str);
+        if ($found instanceof Group_alias) {
+            return $found->getProfile();
+        }
+
+        return null;
     }
 }
 
@@ -281,11 +325,11 @@ class NicknamePathCollisionException extends NicknameException
 
 class NicknameTakenException extends NicknameException
 {
-    public $user = null;    // the User which occupies the nickname
+    public $profile = null;    // the Profile which occupies the nickname
 
-    public function __construct(User $user, $msg=null, $code=400)
+    public function __construct(Profile $profile, $msg=null, $code=400)
     {
-        $this->byuser = $user;
+        $this->profile = $profile;
 
         if ($msg === null) {
             $msg = $this->defaultMessage();