]> Untitled Git - lemmy.git/commitdiff
Merge branch 'master' into federation
authorFelix Ableitner <me@nutomic.com>
Tue, 9 Jun 2020 12:01:26 +0000 (14:01 +0200)
committerFelix Ableitner <me@nutomic.com>
Tue, 9 Jun 2020 12:01:26 +0000 (14:01 +0200)
16 files changed:
1  2 
README.md
docker/dev/docker-compose.yml
docs/src/contributing_federation_development.md
server/Cargo.toml
server/src/api/user.rs
server/src/lib.rs
server/src/main.rs
server/src/routes/websocket.rs
ui/src/components/comment-node.tsx
ui/src/components/main.tsx
ui/src/components/post-form.tsx
ui/src/components/post-listing.tsx
ui/src/components/private-message-form.tsx
ui/src/components/sidebar.tsx
ui/src/components/user.tsx
ui/src/utils.ts

diff --cc README.md
Simple merge
Simple merge
index ddc6e7666389183e049d310462db18a84f755e12,e658f03ad67dfc7246306c3c49b918daa7f4a2f9..47be3239ebd3f12c317d573c0b0800fc0438ff41
@@@ -5,16 -5,14 +5,16 @@@ authors = ["Dessalines <tyhou13@gmx.com
  edition = "2018"
  
  [dependencies]
 -diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2", "64-column-tables"] }
 +diesel = { version = "1.4.4", features = ["postgres","chrono","r2d2","64-column-tables","serde_json"] }
  diesel_migrations = "1.4.0"
  dotenv = "0.15.0"
 -bcrypt = "0.7.0"
 -activitypub = "0.2.0"
 +activitystreams = "0.6.2"
 +activitystreams-new = { git = "https://git.asonix.dog/asonix/activitystreams-sketch" }
 +activitystreams-ext = { git = "https://git.asonix.dog/asonix/activitystreams-ext" }
 +bcrypt = "0.8.0"
  chrono = { version = "0.4.7", features = ["serde"] }
- failure = "0.1.8"
 +serde_json = { version = "1.0.48", features = ["preserve_order"]}
+ failure = "0.1.8"
 -serde_json = { version = "1.0.52", features = ["preserve_order"]}
  serde = { version = "1.0.105", features = ["derive"] }
  actix = "0.9.0"
  actix-web = "2.0.0"
index 18d309850840a4edf6b8c8d235cb03f300a6c20f,ee57723a1e6cb35888878b8c553d14343b39ea15..f68a1a82b7c1f48e642a2e7c96a5e075b589fec2
@@@ -1,57 -1,6 +1,58 @@@
 -use super::*;
 -use crate::is_valid_username;
 +use crate::{
 +  api::{APIError, Oper, Perform},
 +  apub::{
 +    extensions::signatures::generate_actor_keypair,
 +    make_apub_endpoint,
 +    ApubObjectType,
 +    EndpointType,
 +  },
 +  db::{
 +    comment::*,
 +    comment_view::*,
 +    community::*,
 +    community_view::*,
 +    moderator::*,
 +    password_reset_request::*,
 +    post::*,
 +    post_view::*,
 +    private_message::*,
 +    private_message_view::*,
 +    site::*,
 +    site_view::*,
 +    user::*,
 +    user_mention::*,
 +    user_mention_view::*,
 +    user_view::*,
 +    Crud,
 +    Followable,
 +    Joinable,
 +    ListingType,
 +    SortType,
 +  },
 +  generate_random_string,
++  is_valid_username,
 +  naive_from_unix,
 +  naive_now,
 +  remove_slurs,
 +  send_email,
 +  settings::Settings,
 +  slur_check,
 +  slurs_vec_to_str,
 +  websocket::{
 +    server::{JoinUserRoom, SendAllMessage, SendUserRoomMessage},
 +    UserOperation,
 +    WebsocketInfo,
 +  },
 +};
  use bcrypt::verify;
 +use diesel::{
 +  r2d2::{ConnectionManager, Pool},
 +  PgConnection,
 +};
 +use failure::Error;
 +use log::error;
 +use serde::{Deserialize, Serialize};
 +use std::str::FromStr;
  
  #[derive(Serialize, Deserialize, Debug)]
  pub struct Login {
@@@ -313,7 -262,9 +314,10 @@@ impl Perform for Oper<Register> 
        return Err(APIError::err("admin_already_created").into());
      }
  
 +    let user_keypair = generate_actor_keypair()?;
+     if !is_valid_username(&data.username) {
+       return Err(APIError::err("invalid_username").into());
+     }
  
      // Register the new user
      let user_form = UserForm {
index 055cc5f7ab083183c3df58738b176c81e78a03d4,ca4bedea7b09162ff79725053c40d2b89a9510c6..32c374390e8bc37769cdbaa30ec2e0d5136393e4
@@@ -241,53 -269,26 +267,68 @@@ pub fn get_ip(conn_info: &ConnectionInf
      .to_string()
  }
  
 +// TODO nothing is done with community / group webfingers yet, so just ignore those for now
 +#[derive(Clone, PartialEq, Eq, Hash)]
 +pub struct MentionData {
 +  pub name: String,
 +  pub domain: String,
 +}
 +
 +impl MentionData {
 +  pub fn is_local(&self) -> bool {
 +    Settings::get().hostname.eq(&self.domain)
 +  }
 +  pub fn full_name(&self) -> String {
 +    format!("@{}@{}", &self.name, &self.domain)
 +  }
 +}
 +
 +pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
 +  let mut out: Vec<MentionData> = Vec::new();
 +  for caps in WEBFINGER_USER_REGEX.captures_iter(text) {
 +    out.push(MentionData {
 +      name: caps["name"].to_string(),
 +      domain: caps["domain"].to_string(),
 +    });
 +  }
 +  out.into_iter().unique().collect()
 +}
 +
+ pub fn is_valid_username(name: &str) -> bool {
+   VALID_USERNAME_REGEX.is_match(name)
+ }
  #[cfg(test)]
  mod tests {
    use crate::{
 -    extract_usernames, is_email_regex, is_image_content_type, is_valid_username, remove_slurs,
 -    slur_check, slurs_vec_to_str,
 +    is_email_regex,
++    is_image_content_type,
++    is_valid_username,
 +    remove_slurs,
 +    scrape_text_for_mentions,
 +    slur_check,
 +    slurs_vec_to_str,
    };
  
 +  #[test]
 +  fn test_mentions_regex() {
 +    let text = "Just read a great blog post by [@tedu@honk.teduangst.com](/u/test). And another by !test_community@fish.teduangst.com . Another [@lemmy@lemmy_alpha:8540](/u/fish)";
 +    let mentions = scrape_text_for_mentions(text);
 +
 +    assert_eq!(mentions[0].name, "tedu".to_string());
 +    assert_eq!(mentions[0].domain, "honk.teduangst.com".to_string());
 +    assert_eq!(mentions[1].domain, "lemmy_alpha:8540".to_string());
 +  }
 +
+   #[test]
+   fn test_image() {
+     assert!(is_image_content_type("https://1734811051.rsc.cdn77.org/data/images/full/365645/as-virus-kills-navajos-in-their-homes-tribal-women-provide-lifeline.jpg?w=600?w=650").is_ok());
+     assert!(is_image_content_type(
+       "https://twitter.com/BenjaminNorton/status/1259922424272957440?s=20"
+     )
+     .is_err());
+   }
    #[test]
    fn test_email() {
      assert!(is_email_regex("gush@gmail.com"));
@@@ -348,7 -365,5 +398,8 @@@ lazy_static! 
    static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
    static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?|maricos?|cock\s?sucker(s|ing)?|nig(\b|g?(a|er)?(s|z)?)\b|dindu(s?)|mudslime?s?|kikes?|mongoloids?|towel\s*heads?|\bspi(c|k)s?\b|\bchinks?|niglets?|beaners?|\bnips?\b|\bcoons?\b|jungle\s*bunn(y|ies?)|jigg?aboo?s?|\bpakis?\b|rag\s*heads?|gooks?|cunts?|bitch(es|ing|y)?|puss(y|ies?)|twats?|feminazis?|whor(es?|ing)|\bslut(s|t?y)?|\btrann?(y|ies?)|ladyboy(s?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().unwrap();
    static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").unwrap();
 +  // TODO keep this old one, it didn't work with port well tho
 +  // static ref WEBFINGER_USER_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").unwrap();
 +  static ref WEBFINGER_USER_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").unwrap();
+   static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap();
  }
index 4339e5f06f4f9824682b4fac0c006d3881de222b,3f91965e10a84b252f8ce600edb1e6fd70ee61b4..2f53f3ac68f92e40fd110c4725ca8fb03faead6c
@@@ -1,16 -1,19 +1,26 @@@
  extern crate lemmy_server;
  #[macro_use]
  extern crate diesel_migrations;
+ #[macro_use]
+ pub extern crate lazy_static;
  
+ use crate::lemmy_server::actix_web::dev::Service;
  use actix::prelude::*;
 -use actix_web::body::Body;
 -use actix_web::dev::{ServiceRequest, ServiceResponse};
 -use actix_web::http::header::CONTENT_TYPE;
 -use actix_web::http::{header::CACHE_CONTROL, HeaderValue};
--use actix_web::*;
 -use diesel::r2d2::{ConnectionManager, Pool};
 -use diesel::PgConnection;
++use actix_web::{
++  body::Body,
++  dev::{ServiceRequest, ServiceResponse},
++  http::{
++    header::{CACHE_CONTROL, CONTENT_TYPE},
++    HeaderValue,
++  },
++  *,
++};
 +use diesel::{
 +  r2d2::{ConnectionManager, Pool},
 +  PgConnection,
 +};
- use failure::Error;
  use lemmy_server::{
 +  db::code_migrations::run_advanced_migrations,
    rate_limit::{rate_limiter::RateLimiter, RateLimit},
    routes::{api, federation, feeds, index, nodeinfo, webfinger},
    settings::Settings,
Simple merge
Simple merge
Simple merge
index f04910bee2134f18633c3974096366854e3b78b0,6f1e34e01417e0e2b1a25dff00d6b2baf0e2df42..22224c344af941f312ed08fab90864b57e0dbe93
@@@ -331,12 -330,9 +331,13 @@@ export class PostForm extends Component
                    value={this.state.postForm.community_id}
                    onInput={linkEvent(this, this.handlePostCommunityChange)}
                  >
+                   <option>{i18n.t('select_a_community')}</option>
                    {this.state.communities.map(community => (
 -                    <option value={community.id}>{community.name}</option>
 +                    <option value={community.id}>
 +                      {community.local
 +                        ? community.name
 +                        : `${hostname(community.actor_id)}/${community.name}`}
 +                    </option>
                    ))}
                  </select>
                </div>
Simple merge
Simple merge
Simple merge
diff --cc ui/src/utils.ts
index 54322c8b2a88243b9af36fdc0b720fd141a85695,3bad50404cbc1c058986c0c1e83c52a2a2ee4d50..5ce84b39d915f6ef26a977df86be4b05ab2a472b
@@@ -858,9 -882,20 +898,27 @@@ export function previewLines(text: stri
      .join('\n');
  }
  
 +export function hostname(url: string): string {
 +  let cUrl = new URL(url);
 +  return window.location.port
 +    ? `${cUrl.hostname}:${cUrl.port}`
 +    : `${cUrl.hostname}`;
 +}
++
+ function canUseWebP() {
+   // TODO pictshare might have a webp conversion bug, try disabling this
+   return false;
+   // var elem = document.createElement('canvas');
+   // if (!!(elem.getContext && elem.getContext('2d'))) {
+   //   var testString = !(window.mozInnerScreenX == null) ? 'png' : 'webp';
+   //   // was able or not to get WebP representation
+   //   return (
+   //     elem.toDataURL('image/webp').startsWith('data:image/' + testString)
+   //   );
+   // }
+   // // very old browser like IE 8, canvas not supported
+   // return false;
+ }