1# coding=utf-8 2from __future__ import unicode_literals 3 4from text_unidecode import unidecode 5 6from .. import BaseProvider 7 8from ipaddress import ip_address, ip_network, IPV4LENGTH, IPV6LENGTH 9 10# from faker.generator import random 11# from faker.providers.lorem.la import Provider as Lorem 12from faker.utils.decorators import lowercase, slugify, slugify_unicode 13 14 15localized = True 16 17 18IPV4_PUBLIC_NETS = { 19 'a': ip_network('0.0.0.0/1'), 20 'b': ip_network('128.0.0.0/2'), 21 'c': ip_network('192.0.0.0/3') 22} 23IPV4_PRIVATE_NET_BLOCKS = { 24 'a': ( 25 ip_network('0.0.0.0/8'), 26 ip_network('10.0.0.0/8'), 27 ip_network('127.0.0.0/8'), 28 ), 29 'b': ( 30 ip_network('169.254.0.0/16'), 31 ip_network('172.16.0.0/12') 32 ), 33 'c': ( 34 ip_network('192.0.0.0/29'), 35 ip_network('192.0.0.170/31'), 36 ip_network('192.0.2.0/24'), 37 ip_network('192.168.0.0/16'), 38 ip_network('198.18.0.0/15'), 39 ip_network('198.51.100.0/24'), 40 ip_network('203.0.113.0/24') 41 ), 42} 43IPV4_NET_CLASSES = { 44 'a': (167772160, 184549375, 24), 45 'b': (2886729728, 2887778303, 20), 46 'c': (3232235520, 3232301055, 16) 47} 48 49 50class Provider(BaseProvider): 51 safe_email_tlds = ('org', 'com', 'net') 52 free_email_domains = ('gmail.com', 'yahoo.com', 'hotmail.com') 53 tlds = ( 54 'com', 'com', 'com', 'com', 'com', 'com', 'biz', 'info', 'net', 'org' 55 ) 56 57 uri_pages = ( 58 'index', 'home', 'search', 'main', 'post', 'homepage', 'category', 59 'register', 'login', 'faq', 'about', 'terms', 'privacy', 'author' 60 ) 61 uri_paths = ( 62 'app', 'main', 'wp-content', 'search', 'category', 'tag', 'categories', 63 'tags', 'blog', 'posts', 'list', 'explore' 64 ) 65 uri_extensions = ( 66 '.html', '.html', '.html', '.htm', '.htm', '.php', '.php', '.jsp', 67 '.asp' 68 ) 69 70 user_name_formats = ( 71 '{{last_name}}.{{first_name}}', 72 '{{first_name}}.{{last_name}}', 73 '{{first_name}}##', 74 '?{{last_name}}', 75 ) 76 email_formats = ( 77 '{{user_name}}@{{domain_name}}', 78 '{{user_name}}@{{free_email_domain}}', 79 ) 80 url_formats = ( 81 'www.{{domain_name}}/', 82 '{{domain_name}}/', 83 ) 84 uri_formats = ( 85 '{{url}}', 86 '{{url}}{{uri_page}}/', 87 '{{url}}{{uri_page}}{{uri_extension}}', 88 '{{url}}{{uri_path}}/{{uri_page}}/', 89 '{{url}}{{uri_path}}/{{uri_page}}{{uri_extension}}', 90 ) 91 image_placeholder_services = ( 92 'https://placeholdit.imgix.net/~text' 93 '?txtsize=55&txt={width}x{height}&w={width}&h={height}', 94 'https://www.lorempixel.com/{width}/{height}', 95 'https://dummyimage.com/{width}x{height}', 96 ) 97 98 replacements = tuple() 99 100 def _to_ascii(self, string): 101 for search, replace in self.replacements: 102 string = string.replace(search, replace) 103 104 string = unidecode(string) 105 return string 106 107 @lowercase 108 def email(self, domain=None): 109 if domain: 110 email = '{0}@{1}'.format(self.user_name(), domain) 111 else: 112 pattern = self.random_element(self.email_formats) 113 email = "".join(self.generator.parse(pattern).split(" ")) 114 return email 115 116 @lowercase 117 def safe_email(self): 118 return '{}@example.{}'.format( 119 self.user_name(), self.random_element(self.safe_email_tlds) 120 ) 121 122 @lowercase 123 def free_email(self): 124 return self.user_name() + '@' + self.free_email_domain() 125 126 @lowercase 127 def company_email(self): 128 return self.user_name() + '@' + self.domain_name() 129 130 @lowercase 131 def free_email_domain(self): 132 return self.random_element(self.free_email_domains) 133 134 @lowercase 135 def ascii_email(self): 136 pattern = self.random_element(self.email_formats) 137 return self._to_ascii( 138 "".join(self.generator.parse(pattern).split(" ")) 139 ) 140 141 @lowercase 142 def ascii_safe_email(self): 143 return self._to_ascii( 144 self.user_name() + 145 '@example.' + 146 self.random_element(self.safe_email_tlds) 147 ) 148 149 @lowercase 150 def ascii_free_email(self): 151 return self._to_ascii( 152 self.user_name() + '@' + self.free_email_domain() 153 ) 154 155 @lowercase 156 def ascii_company_email(self): 157 return self._to_ascii( 158 self.user_name() + '@' + self.domain_name() 159 ) 160 161 @slugify_unicode 162 def user_name(self): 163 pattern = self.random_element(self.user_name_formats) 164 username = self._to_ascii( 165 self.bothify(self.generator.parse(pattern)).lower() 166 ) 167 return username 168 169 @lowercase 170 def domain_name(self, levels=1): 171 """ 172 Produce an Internet domain name with the specified number of 173 subdomain levels. 174 175 >>> domain_name() 176 nichols-phillips.com 177 >>> domain_name(2) 178 williamson-hopkins.jackson.com 179 """ 180 if levels < 1: 181 raise ValueError("levels must be greater than or equal to 1") 182 if levels == 1: 183 return self.domain_word() + '.' + self.tld() 184 else: 185 return self.domain_word() + '.' + self.domain_name(levels - 1) 186 187 @lowercase 188 @slugify_unicode 189 def domain_word(self,): 190 company = self.generator.format('company') 191 company_elements = company.split(' ') 192 company = self._to_ascii(company_elements.pop(0)) 193 return company 194 195 def tld(self): 196 return self.random_element(self.tlds) 197 198 def url(self, schemes=None): 199 """ 200 :param schemes: a list of strings to use as schemes, one will chosen randomly. 201 If None, it will generate http and https urls. 202 Passing an empty list will result in schemeless url generation like "://domain.com". 203 204 :returns: a random url string. 205 """ 206 if schemes is None: 207 schemes = ['http', 'https'] 208 209 pattern = '{}://{}'.format( 210 self.random_element(schemes) if schemes else "", 211 self.random_element(self.url_formats) 212 ) 213 214 return self.generator.parse(pattern) 215 216 def ipv4(self, network=False, address_class=None, private=None): 217 """ 218 Produce a random IPv4 address or network with a valid CIDR. 219 220 :param network: Network address 221 :param address_class: IPv4 address class (a, b, or c) 222 :param private: Public or private 223 :returns: IPv4 224 """ 225 if private is True: 226 return self.ipv4_private(address_class=address_class, 227 network=network) 228 elif private is False: 229 return self.ipv4_public(address_class=address_class, 230 network=network) 231 if address_class is None: 232 ip_range = (0, (2 ** IPV4LENGTH) - 1) 233 else: 234 net = IPV4_PUBLIC_NETS[address_class] 235 ip_range = (net._ip[0], net.ip[-1]) 236 address = str(ip_address(self.generator.random.randint(*ip_range))) 237 if network: 238 address += '/' + str(self.generator.random.randint(0, IPV4LENGTH)) 239 address = str(ip_network(address, strict=False)) 240 return address 241 242 def ipv4_network_class(self): 243 """ 244 Returns a IPv4 network class 'a', 'b' or 'c'. 245 246 :returns: IPv4 network class 247 """ 248 return self.random_element('abc') 249 250 def ipv4_private(self, network=False, address_class=None): 251 """ 252 Returns a private IPv4. 253 254 :param network: Network address 255 :param address_class: IPv4 address class (a, b, or c) 256 :returns: Private IPv4 257 """ 258 address_class = address_class or self.ipv4_network_class() 259 min_, max_, netmask = IPV4_NET_CLASSES[address_class] 260 address = str(ip_address( 261 self.generator.random.randint(min_, max_))) 262 if network: 263 address += '/' + str(self.generator.random.randint(netmask, 31)) 264 address = str(ip_network(address, strict=False)) 265 return address 266 267 def ipv4_public(self, network=False, address_class=None): 268 """ 269 Returns a public IPv4 excluding private blocks. 270 271 :param network: Network address 272 :param address_class: IPv4 address class (a, b, or c) 273 :returns: Public IPv4 274 """ 275 address_class = address_class or self.ipv4_network_class() 276 public_net = IPV4_PUBLIC_NETS[address_class] 277 private_blocks = IPV4_PRIVATE_NET_BLOCKS[address_class] 278 # Make valid IP ranges, created from private block exclusion 279 net_ranges = [] 280 ## Starts at end of 1st block if it's 1st of class 281 if public_net[0] != private_blocks[0][0]: 282 net_ranges = [(public_net[0]._ip, private_blocks[0][0]._ip-1)] 283 ## Loop on private blocks and guess available ranges 284 for i, block in enumerate(private_blocks): 285 if i+1 == len(private_blocks): 286 break 287 net_range = (block[-1]._ip+1, private_blocks[i+1][0]._ip-1) 288 net_ranges.append(net_range) 289 ## Add last range 290 net_ranges.append((private_blocks[-1][-1]._ip-1, public_net[-1]._ip-1)) 291 net_ranges = [(i, j) for i, j in net_ranges if (j-i) > 0] 292 # Choose a range 293 min_, max_ = self.generator.random.choice(net_ranges) 294 address = str(ip_address( 295 self.generator.random.randint(min_, max_))) 296 # Add network mask 297 if network: 298 net_masks = {'a': 8, 'b': 16, 'c': 24} 299 min_net_mask = net_masks[address_class] 300 address += '/' + str(self.generator.random.randint(min_net_mask, 31)) 301 address = str(ip_network(address, strict=False)) 302 return address 303 304 def ipv6(self, network=False): 305 """Produce a random IPv6 address or network with a valid CIDR""" 306 address = str(ip_address(self.generator.random.randint( 307 2 ** IPV4LENGTH, (2 ** IPV6LENGTH) - 1))) 308 if network: 309 address += '/' + str(self.generator.random.randint(0, IPV6LENGTH)) 310 address = str(ip_network(address, strict=False)) 311 return address 312 313 def mac_address(self): 314 mac = [self.generator.random.randint(0x00, 0xff) for _ in range(0, 6)] 315 return ":".join(map(lambda x: "%02x" % x, mac)) 316 317 def uri_page(self): 318 return self.random_element(self.uri_pages) 319 320 def uri_path(self, deep=None): 321 deep = deep if deep else self.generator.random.randint(1, 3) 322 return "/".join( 323 [self.random_element(self.uri_paths) for _ in range(0, deep)] 324 ) 325 326 def uri_extension(self): 327 return self.random_element(self.uri_extensions) 328 329 def uri(self): 330 pattern = self.random_element(self.uri_formats) 331 return self.generator.parse(pattern) 332 333 @slugify 334 def slug(self, value=None): 335 """Django algorithm""" 336 if value is None: 337 value = self.generator.text(20) 338 return value 339 340 def image_url(self, width=None, height=None): 341 """ 342 Returns URL to placeholder image 343 Example: http://placehold.it/640x480 344 """ 345 width_ = width or self.random_int(max=1024) 346 height_ = height or self.random_int(max=1024) 347 placeholder_url = self.random_element(self.image_placeholder_services) 348 return placeholder_url.format(width=width_, height=height_) 349