Nogo areas for spoofed locations, to avoid rivers or sea

merge-requests/30/head
Bob Mottram 2021-06-08 13:50:25 +01:00
parent 4899fdea28
commit 69f9938846
4 changed files with 156 additions and 22 deletions

132
city.py
View File

@ -126,10 +126,45 @@ def _getCityPulse(currTimeOfDay, decoySeed: int) -> (float, float):
return distanceFromCityCenter, angleRadians
def parseNogoString(nogoLine: str) -> []:
"""Parses a line from locations_nogo.txt and returns the polygon
"""
polygonStr = nogoLine.split(':', 1)[1]
if ';' in polygonStr:
pts = polygonStr.split(';')
else:
pts = polygonStr.split(',')
if len(pts) <= 4:
return []
polygon = []
for index in range(int(len(pts)/2)):
if index*2 + 1 >= len(pts):
break
longitudeStr = pts[index*2].strip()
latitudeStr = pts[index*2 + 1].strip()
if 'E' in latitudeStr or 'W' in latitudeStr:
longitudeStr = pts[index*2 + 1].strip()
latitudeStr = pts[index*2].strip()
if 'E' in longitudeStr:
longitudeStr = \
longitudeStr.replace('E', '')
longitude = float(longitudeStr)
elif 'W' in longitudeStr:
longitudeStr = \
longitudeStr.replace('W', '')
longitude = -float(longitudeStr)
else:
longitude = float(longitudeStr)
latitude = float(latitudeStr)
polygon.append([latitude, longitude])
return polygon
def spoofGeolocation(baseDir: str,
city: str, currTime, decoySeed: int,
citiesList: []) -> (float, float, str, str,
str, str, int):
citiesList: [],
nogoList: []) -> (float, float, str, str,
str, str, int):
"""Given a city and the current time spoofs the location
for an image
returns latitude, longitude, N/S, E/W,
@ -138,6 +173,11 @@ def spoofGeolocation(baseDir: str,
locationsFilename = baseDir + '/custom_locations.txt'
if not os.path.isfile(locationsFilename):
locationsFilename = baseDir + '/locations.txt'
nogoFilename = baseDir + '/custom_locations_nogo.txt'
if not os.path.isfile(nogoFilename):
nogoFilename = baseDir + '/locations_nogo.txt'
manCityRadius = 0.1
varianceAtLocation = 0.0004
default_latitude = 51.8744
@ -156,6 +196,19 @@ def spoofGeolocation(baseDir: str,
with open(locationsFilename, "r") as f:
cities = f.readlines()
nogo = []
if nogoList:
nogo = nogoList
else:
if os.path.isfile(nogoFilename):
with open(nogoFilename, "r") as f:
nogoList = f.readlines()
for line in nogoList:
if line.startswith(city + ':'):
polygon = parseNogoString(line)
if polygon:
nogo.append(polygon)
city = city.lower()
for cityName in cities:
if city in cityName.lower():
@ -183,22 +236,35 @@ def spoofGeolocation(baseDir: str,
datetime.timedelta(hours=approxTimeZone)
camMake, camModel, camSerialNumber = \
_getDecoyCamera(decoySeed)
# patterns of activity change in the city over time
(distanceFromCityCenter, angleRadians) = \
_getCityPulse(currTimeAdjusted, decoySeed)
# The city radius value is in longitude and the reference
# is Manchester. Adjust for the radius of the chosen city.
if areaKm2 > 1:
manRadius = math.sqrt(630 / math.pi)
radius = math.sqrt(areaKm2 / math.pi)
cityRadius = manCityRadius * manRadius / radius
else:
cityRadius = manCityRadius
# Get the position within the city, with some randomness added
latitude += \
distanceFromCityCenter * cityRadius * math.cos(angleRadians)
longitude += \
distanceFromCityCenter * cityRadius * math.sin(angleRadians)
validCoord = False
seedOffset = 0
while not validCoord:
# patterns of activity change in the city over time
(distanceFromCityCenter, angleRadians) = \
_getCityPulse(currTimeAdjusted, decoySeed + seedOffset)
# The city radius value is in longitude and the reference
# is Manchester. Adjust for the radius of the chosen city.
if areaKm2 > 1:
manRadius = math.sqrt(630 / math.pi)
radius = math.sqrt(areaKm2 / math.pi)
cityRadius = manCityRadius * manRadius / radius
else:
cityRadius = manCityRadius
# Get the position within the city, with some randomness added
latitude += \
distanceFromCityCenter * cityRadius * \
math.cos(angleRadians)
longitude += \
distanceFromCityCenter * cityRadius * \
math.sin(angleRadians)
longval = longitude
if longdirection == 'W':
longval = -longitude
validCoord = not pointInNogo(nogo, latitude, longval)
if not validCoord:
seedOffset += 1
if seedOffset > 100:
break
# add a small amount of variance around the location
fraction = randint(0, 100000) / 100000
distanceFromLocation = fraction * fraction * varianceAtLocation
@ -229,3 +295,33 @@ def getSpoofedCity(city: str, baseDir: str, nickname: str, domain: str) -> str:
with open(cityFilename, 'r') as fp:
city = fp.read().replace('\n', '')
return city
def _pointInPolygon(poly: [], x: float, y: float) -> bool:
"""Returns true if the given point is inside the given polygon
"""
n = len(poly)
inside = False
p2x = 0.0
p2y = 0.0
xints = 0.0
p1x, p1y = poly[0]
for i in range(n + 1):
p2x, p2y = poly[i % n]
if y > min(p1y, p2y):
if y <= max(p1y, p2y):
if x <= max(p1x, p2x):
if p1y != p2y:
xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
if p1x == p2x or x <= xints:
inside = not inside
p1x, p1y = p2x, p2y
return inside
def pointInNogo(nogo: [], latitude: float, longitude: float) -> bool:
for polygon in nogo:
if _pointInPolygon(polygon, latitude, longitude):
return True
return False

View File

@ -0,0 +1,2 @@
NEW YORK, USA: 73.951W,40.879, 73.974W,40.83, 74.029W,40.756, 74.038W,40.713, 74.056W,40.713, 74.127W,40.647, 74.038W,40.629, 73.995W,40.667, 74.014W,40.676, 73.994W,40.702, 73.967W,40.699, 73.958W,40.729, 73.956W,40.745, 73.918W,40.781, 73.937W,40.793, 73.946W,40.782, 73.977W,40.738, 73.98W,40.713, 74.012W,40.705, 74.006W,40.752, 73.955W,40.824
NEW YORK, USA: 74.115W,40.663, 74.065W,40.602, 74.118W,40.555, 74.047W,40.516, 73.882W,40.547, 73.909W,40.618, 73.978W,40.579, 74.009W,40.602, 74.033W,40.61, 74.039W,40.623, 74.032W,40.641, 73.996W,40.665

View File

@ -87,7 +87,7 @@ def _spoofMetaData(baseDir: str, nickname: str, domain: str,
(latitude, longitude, latitudeRef, longitudeRef,
camMake, camModel, camSerialNumber) = \
spoofGeolocation(baseDir, spoofCity, currTimeAdjusted,
decoySeed, None)
decoySeed, None, None)
os.system('exiftool -artist="' + nickname + '" ' +
'-Make="' + camMake + '" ' +
'-Model="' + camModel + '" ' +

View File

@ -81,7 +81,9 @@ from like import likePost
from like import sendLikeViaServer
from announce import announcePublic
from announce import sendAnnounceViaServer
from city import parseNogoString
from city import spoofGeolocation
from city import pointInNogo
from media import getMediaPath
from media import getAttachmentMediaType
from delete import sendDeleteViaServer
@ -3605,6 +3607,19 @@ def testRemovePostInteractions() -> None:
def testSpoofGeolocation() -> None:
print('testSpoofGeolocation')
nogoLine = \
'NEW YORK, USA: 73.951W,40.879, 73.974W,40.83, ' + \
'74.029W,40.756, 74.038W,40.713, 74.056W,40.713, ' + \
'74.127W,40.647, 74.038W,40.629, 73.995W,40.667, ' + \
'74.014W,40.676, 73.994W,40.702, 73.967W,40.699, ' + \
'73.958W,40.729, 73.956W,40.745, 73.918W,40.781, ' + \
'73.937W,40.793, 73.946W,40.782, 73.977W,40.738, ' + \
'73.98W,40.713, 74.012W,40.705, 74.006W,40.752, ' + \
'73.955W,40.824'
polygon = parseNogoString(nogoLine)
assert len(polygon) > 0
assert polygon[0][1] == -73.951
assert polygon[0][0] == 40.879
citiesList = [
'NEW YORK, USA:40.7127281:W74.0060152:784',
'LOS ANGELES, USA:34.0536909:W118.242766:1214',
@ -3613,11 +3628,23 @@ def testSpoofGeolocation() -> None:
'BERLIN, GERMANY:52.5170365:13.3888599:891',
'ANKARA, TURKEY:39.93:32.85:24521'
]
testSquare = [
[[0.03, 0.01], [0.02, 10], [10.01, 10.02], [10.03, 0.02]]
]
assert pointInNogo(testSquare, 5, 5)
assert pointInNogo(testSquare, 2, 3)
assert not pointInNogo(testSquare, 20, 5)
assert not pointInNogo(testSquare, 11, 6)
assert not pointInNogo(testSquare, 5, -5)
assert not pointInNogo(testSquare, 5, 11)
assert not pointInNogo(testSquare, -5, -5)
assert not pointInNogo(testSquare, -5, 5)
nogoList = []
currTime = datetime.datetime.utcnow()
decoySeed = 7634681
cityRadius = 0.1
coords = spoofGeolocation('', 'los angeles', currTime,
decoySeed, citiesList)
decoySeed, citiesList, nogoList)
assert coords[0] >= 34.0536909 - cityRadius
assert coords[0] <= 34.0536909 + cityRadius
assert coords[1] >= 118.242766 - cityRadius
@ -3627,8 +3654,9 @@ def testSpoofGeolocation() -> None:
assert len(coords[4]) > 4
assert len(coords[5]) > 4
assert coords[6] > 0
nogoList = []
coords = spoofGeolocation('', 'unknown', currTime,
decoySeed, citiesList)
decoySeed, citiesList, nogoList)
assert coords[0] >= 51.8744 - cityRadius
assert coords[0] <= 51.8744 + cityRadius
assert coords[1] >= 0.368333 - cityRadius
@ -3641,6 +3669,14 @@ def testSpoofGeolocation() -> None:
kmlStr = '<?xml version="1.0" encoding="UTF-8"?>\n'
kmlStr += '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
kmlStr += '<Document>\n'
nogoLine2 = \
'NEW YORK, USA: 74.115W,40.663, 74.065W,40.602, ' + \
'74.118W,40.555, 74.047W,40.516, 73.882W,40.547, ' + \
'73.909W,40.618, 73.978W,40.579, 74.009W,40.602, ' + \
'74.033W,40.61, 74.039W,40.623, 74.032W,40.641, ' + \
'73.996W,40.665'
polygon2 = parseNogoString(nogoLine2)
nogoList = [polygon, polygon2]
for i in range(1000):
dayNumber = randint(10, 30)
hour = randint(1, 23)
@ -3651,7 +3687,7 @@ def testSpoofGeolocation() -> None:
" " + hourStr + ":14",
"%Y-%m-%d %H:%M")
coords = spoofGeolocation('', 'new york, usa', currTime,
decoySeed, citiesList)
decoySeed, citiesList, nogoList)
longitude = coords[1]
if coords[3] == 'W':
longitude = -coords[1]